Semantic Kernel 引导式对话框架(Guided Conversations)完整指南:让 Agent 目标明确、节奏可控地主导对话
【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel
导读
本文围绕 Semantic Kernel Python 仓库中的python/samples/demos/guided_conversations示例,系统讲解引导式对话(Guided Conversations)这一 Agent 设计模式:由带目标与约束的 Agent(作为"创造者")主导一段与用户的多轮对话,并在过程中持续生成表单、笔记、计划等"产物(artifact)"。读完本文,你将掌握该框架的五大输入要素(产物、规则、对话流程、上下文、资源约束)、其"用模型思考、用代码规划"(think with the model, plan with the code)的核心设计原则,以及如何基于 Semantic Kernel 的 Kernel/插件机制落地一套可靠的对话编排实现。
什么是引导式对话(Guided Conversations)
日常生活中大量对话场景都有一个共同特征:一方带着明确目标和约束来主导对话,另一方参与其中。例如:
- 老师引导学生完成一堂课;
- 呼叫中心坐席收集客户问题的信息;
- 销售代表帮助客户找到满足其需求的产品;
- 面试官通过一系列问题评估候选人与岗位的匹配度;
- 护士通过系列问题对患者症状的严重程度进行分诊;
- 会议中参与者轮流汇报进展并讨论下一步。
这些场景的共同点是:发生在"创造者(creator)"(主导对话的一方)与"用户(user(s))"(参与方)之间。创造者定义目标、规划对话如何流动,并通常在对话过程中通过一张"表单"收集关键信息;ta 必须运用判断力让对话始终朝既定目标推进,同时提前记录关键信息与规划。
该示例的目标正是:构建一个通用框架,创建能够半自主地辅助创造者运行对话场景的 AI Agent,并产出可用于追踪进度与结果的产物(artifact),例如笔记、表单和计划。该框架有一条关键准则:think with the model, plan with the code(用模型思考,用代码规划)——即模型负责理解用户输入并做出复杂决策,而代码负责施加约束和提供结构,从而使系统可靠(reliable)。
对应到源码,这段框架的核心实现在 guided_conversation_agent.py 中,其GuidedConversation类聚合了会话记录、资源计数器、产物插件与议程插件,并以 Semantic Kernel 的 Kernel 为执行底座(见 guided_conversation_agent.py 的__init__)。
框架要解决的三大挑战
作者团队在开发该示例时,观察到用 Agent 做对话场景时的几个常见痛点,并给出了对应的框架解法:
| 常见挑战 | Guided Conversations 的解法 |
|---|---|
| 聚焦——Agent 容易偏离最初目标 | 将 Agent 的目标定义为"完成一个产物(artifact)",即对话中 Agent 需要完成什么的精确表示 |
| 节奏——对话推进过快、过于冗长、对时间缺乏感知 | 鼓励 Agent 定期更新议程(agenda):每个议程项被分配估算的轮数,时间限制由代码程序化校验,并通过资源约束(resource constraints)将秒/分钟等时间单位程序化转换为轮数(turns) |
| 下游使用——聊天日志难以被进一步处理或分析 | 产物(artifact)既是对话的结构化记录(事后更易分析),也是实时监控 Agent 进度的途径 |
从源码看,这三大挑战分别对应框架中的两个核心插件与一个工具类:Artifact(产物)、Agenda(议程)与GCResource(资源约束),它们都被编排在GuidedConversation主类中(见 guided_conversation_agent.py)。
安装与快速开始
安装
该示例复用 Semantic Kernel Python 源码的开发工具链——poetry,其中semantic-kernel以 git 依赖方式指向仓库main分支的python子目录,Python 版本要求为^3.10,<3.13):
- 在
python/samples/demos/guided_conversations目录下执行poetry install; - 激活 poetry 创建的
.venv虚拟环境; - 为你要使用的 LLM 服务配置环境变量,或准备一个
.env文件; - 如果你向
pyproject.toml中添加了新依赖,运行poetry update。
快速开始
- Fork 本仓库;
- 按上文"安装"步骤安装依赖并配置环境变量;
- 先运行示例 Notebook:01_guided_conversation_teaching.ipynb;
- 为了获得最佳质量与可靠性,建议使用
gpt-4-1106-preview或gpt-4o模型——该示例需要复杂的推理与函数调用(function calling)能力。交互式脚本 interactive_guided_conversation.py 中默认使用的部署即为gpt-4o-2024-05-13。
Notebook 路线图
notebooks/目录下共有 4 个 Notebook,循序渐进地拆解框架:
- 01_guided_conversation_teaching.ipynb:以一个小学教育场景为例,演示完整的引导式对话流程(Agent 引导 4 年级学生 David 完成一首藏头诗,并在结束时输出反馈报告);
- 02_artifact.ipynb:深入讲解产物插件;
- 03_agenda.ipynb:深入讲解议程插件;
- 04_battle_of_the_agents.ipynb:Agent 对战,对比观察不同配置下的行为。
五个输入要素:定义一个引导式对话场景
使用本框架定义新场景时,需要提供以下输入(其中后三个可选):
- 产物(artifact,必填):一个 Pydantic
BaseModel类,定义 Agent 需要在对话中完成的"表单"或"工作记忆"字段; - 规则(rules,必填):Agent 在对话中应遵循的"该做/不该做"(do's and don'ts)列表;
- 对话流程(conversation flow,可选):用自然语言描述对话的步骤(例如"先讲解……再给出指令……然后让学生练习……")。可选的原因是:产物本身有时就可以充当对话流程;当你想提供更多细节或难以用产物结构表达时,使用该字段;
- 上下文(context,可选):对话目标与 Agent 应知道的附加信息,会被置于推理(reasoning)提示词的顶部;
- 资源约束(resource constraint,可选):控制对话长度的约束,包含两个要素:
- 单位(unit):度量长度的方式,已实现
seconds(秒)、minutes(分钟)、turns(轮数);未来可扩展如 token 成本等; - 模式(mode):约束的施加方式,已实现
maximum(上限,Agent 可在资源耗尽前提前结束)与exact(精确,Agent 应恰好用完给定资源)。
- 单位(unit):度量长度的方式,已实现
以上五个输入恰好对应GuidedConversation.__init__的签名(见 guided_conversation_agent.py):artifact: BaseModel、rules: list[str]、conversation_flow: str | None、context: str | None、resource_constraint: ResourceConstraint | None。
核心组件逐层拆解
产物(Artifact):用 Pydantic 建模的"目标即表单"
产物插件位于 artifact.py。它的核心设计是:把 Agent 的目标定义为一个 Pydantic 模型,并在整个对话中鲁棒地(robustly)更新模型字段。
关键机制包括:
- 自动初始化为 "Unanswered":构造时会通过
_modify_base_artifact生成一个新的模型类,为所有字段设置默认值"Unanswered"(见 artifact.py)。因此提示词中'Unanswered'即代表"该字段尚未完成"。 - LLM 值字符串的解析:LLM 返回的值永远是字符串(例如
'["x", "y"]'),因此基类 base_model_llm.py 通过field_validator("*", mode="before")使用ast.literal_eval将字符串解析为正确类型,同时保留纯字符串字段原样;它还设置了validate_assignment = True(每次字段更新都触发校验)与extra = "forbid"(禁止添加额外字段)。 - 带重试的更新循环:核心接口
update_artifact(field_name, field_value, conversation)会尝试更新字段;如果 Pydantic 校验失败(如日期格式不对),会调用 LLM 决定二选一:修复格式后重试更新,或"恢复对话"向用户追问更多信息。重试次数由max_artifact_field_retries控制(默认 2 次,框架主类中固定为MAX_DECISION_RETRIES = 2)。失败的字段会被记录在failed_artifact_fields中,并在更新超过重试上限后被跳过(见 artifact.py)。 - 面向提示词的 Schema 清洗:
get_schema_for_prompt会把原始 JSON Schema 清洗为适合 LLM 阅读的形式(去掉title/default,把$ref替换为type,附带自定义类型说明);get_artifact_for_prompt会返回当前产物状态,但完全省略已失败字段(见 artifact.py)。
产物插件的另一个用法是作为 Agent 的工作记忆(working memory),在对话中持续记录关键信息。
议程(Agenda):让节奏可被规划与校验
议程插件位于 agenda.py。它管理一个由"标题 + 所需轮数"组成的议程项列表(_BaseAgendaItem:title+resource,见 agenda.py)。
- 更新与校验:
update_agenda(items, remaining_turns, conversation)接收 LLM 生成的议程项,通过_validate_agenda_update进行程序化校验,包括:maximum模式下,议程总轮数不得超过剩余轮数;exact模式下,议程总轮数必须恰好等于剩余轮数("不要留下任何未分配的轮数");- 任何一项的资源值都必须大于 0(见 agenda.py)。
- 错误自愈:校验失败时,
_fix_agenda_error调用 LLM 修正议程,且系统提示词明确要求修正必须"最小化改动":不得改变第一项的描述(因为已执行)、不得合并掉已有主题(见 agenda.py)。重试上限由max_agenda_retries控制。 - 提示词友好输出:
get_agenda_for_prompt将议程格式化为带编号、带累计轮数占比的文本,便于放入推理提示词(见 agenda.py)。
资源约束(Resource Constraint):把"时间"翻译成"轮数"
资源约束定义在 resources.py:
- 单位(
ResourceConstraintUnit):SECONDS、MINUTES、TURNS; - 模式(
ResourceConstraintMode):MAXIMUM(上限)与EXACT(精确); - 约束对象(
ResourceConstraint):quantity(数量)+unit+mode三者组合。
GCResource类负责跟踪资源消耗:
start_resource()在每轮对话开始时被调用(对时间单位记录time.time()起点,见 resources.py);increment_resource()在每轮结束时按单位扣减资源并递增turn_number(见 resources.py);estimate_remaining_turns()将秒/分钟单位折算为轮数:基于initial_seconds_per_turn(默认 120 秒/轮)或已观测的平均每轮耗时估算剩余轮数(见 resources.py)。
这里有一处重要的设计取舍:议程校验始终以"轮数"为单位推理——作者团队发现 LLM 以轮数推理效果远好于以秒/分钟推理(见 agenda.py 的注释),因此即便你传入的是秒或分钟约束,也会先被换算成轮数再参与议程规划。get_resource_instructions()还会根据EXACT/MAXIMUM模式生成细致的节奏指示(如exact模式下最后一轮的特殊提示:"不要向用户暗示对话即将结束",见 resources.py)。若resource_constraint为None,则对话可以无限持续,且不会创建议程。
编排器(Orchestrator):两步式"计划-执行"循环
GuidedConversation主类(guided_conversation_agent.py)把以上组件组装成一个可交互的对话循环:
- 注册插件:向 Kernel 注册四个工具——
update_artifact_field(更新产物字段)、update_agenda(更新议程)、send_message_to_user(给用户发消息)、end_conversation(结束对话),并设置req_settings.max_tokens = 2000(见 guided_conversation_agent.py)。 - 两类插件:
plugins_order(普通插件,先执行:更新产物 → 更新议程)与terminal_plugins_order(终结插件,后执行且每轮只能执行一个:发送消息 → 结束对话),执行顺序即列表顺序(见 guided_conversation_agent.py)。 - 单步循环
step_conversation(user_input):这是对外的核心接口,接收用户消息,返回GCOutput(ai_message, is_conversation_over)。其内部是一个"生成计划 → 执行计划"的循环(见 guided_conversation_agent.py):generate_plan:调用 conversation_plan.py 中的conversation_plan_function,不调用任何工具,仅要求模型"逐步推理 + 给出推荐动作及全部所需参数"。这一步是"think with the model"的体现,先显式规划再产生工具调用,已被证明能显著提升可靠性。推理内容还会以REASONING类型的消息加入会话记录(供调试与复盘)。execute_plan:把计划文本作为输入,通过 execution.py 中的execution模板调用FunctionChoiceBehavior.Auto(auto_invoke=False, filters=...)让模型基于计划生成真正的工具调用,再经 openai_tool_calling.py 的parse_function_result与validate_tool_calling做工具名/参数的程序化校验(ToolValidationResult枚举:成功 / 未调用工具 / 调用了意外工具 / 缺少必填参数 / 参数类型错误),并把调用按普通/终结两类排序。- 校验失败最多重试
MAX_DECISION_RETRIES = 2次;若最终仍失败,Agent 会回复错误消息并终止对话。
- 终结收尾
final_update:当模型选择end_conversation时,先调用 final_update_plan.py 的final_update_plan_function,让模型基于完整对话历史最终更新一次产物(例如纠正错误、回填遗漏字段,甚至把错误信息重置为 "Unanswered"),再正式结束对话(见 guided_conversation_agent.py)。 - 可序列化:
to_json/from_json支持将产物、议程、聊天记录、资源状态整体导出与恢复,便于持久化或断点续跑(见 guided_conversation_agent.py)。
实战:定义你自己的场景
下面以交互脚本 interactive_guided_conversation.py 为模板,完整演示如何定义一个新场景(此处为"教 4 年级学生写藏头诗")。该脚本中五个输入的定义方式如下:
1) 产物:任意合法 PydanticBaseModel均可:
from pydantic import BaseModel, Field class MyArtifact(BaseModel): student_poem: str = Field(description="The acrostic poem written by the student.") initial_feedback: str = Field(description="Feedback on the student's final revised poem.") final_feedback: str = Field(description="Feedback on how the student was able to improve their poem.") inappropriate_behavior: list[str] = Field( description="List any inappropriate behavior the student attempted while chatting with you. " "It is ok to leave this field Unanswered if there was none." )2) 规则:do's and don'ts 列表:
rules = [ "DO NOT write the poem for the student.", "Terminate the conversation immediately if the student asks for harmful or inappropriate content.", ]3) 对话流程(可选):自然语言描述步骤,可包含具体示例:
conversation_flow = """1. Start by explaining interactively what an acrostic poem is. 2. Then give the following instructions for how to go ahead and write one: ... 3. Then give the following example of a poem where the word or phrase is HAPPY: ... 4. Finally have the student write their own acrostic poem ... Have them revise their poem based on your feedback and then review it again."""4) 上下文(可选):
context = """You are working 1 on 1 with David, a 4th grade student, who is chatting with you in the computer lab at school while being supervised by their teacher."""5) 资源约束(可选):例如设置精确 10 轮:
from guided_conversation.utils.resources import ( ResourceConstraint, ResourceConstraintMode, ResourceConstraintUnit, ) resource_constraint = ResourceConstraint( quantity=10, unit=ResourceConstraintUnit.TURNS, mode=ResourceConstraintMode.EXACT, )组装与运行:用 Semantic Kernel 构建 Kernel(此处以 Azure OpenAI 为例,也可换成 OpenAI 服务),然后实例化 Agent 并进入交互循环:
import asyncio from azure.identity import AzureCliCredential from semantic_kernel import Kernel from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion from guided_conversation.plugins.guided_conversation_agent import GuidedConversation async def main() -> None: kernel = Kernel() service_id = "gc_main" chat_service = AzureChatCompletion( service_id=service_id, deployment_name="gpt-4o-2024-05-13", api_version="2024-05-01-preview", credential=AzureCliCredential(), ) kernel.add_service(chat_service) guided_conversation_agent = GuidedConversation( kernel=kernel, artifact=MyArtifact, conversation_flow=conversation_flow, context=context, rules=rules, resource_constraint=resource_constraint, service_id=service_id, ) # 与普通聊天机器人不同,引导式对话 Agent 会主动发起第一句话 result = await guided_conversation_agent.step_conversation() print(f"Assistant: {result.ai_message}") while True: try: user_input = input("User: ") except (KeyboardInterrupt, EOFError): print("\n\nExiting chat...") return if user_input == "exit": print("\n\nExiting chat...") return result = await guided_conversation_agent.step_conversation(user_input=user_input) print(f"Assistant: {result.ai_message}") if result.is_conversation_over: return if __name__ == "__main__": asyncio.run(main())对话会在以下三种情况之一结束:用户输入exit/ 中断;Agent 主动结束对话(资源约束耗尽、产物已完成、或用户不配合导致对话无法推进);或出现系统错误。
扩展与复用框架
- 新增场景:参考上文"实战"一节,创建一个新文件并定义产物、规则、(可选)对话流程、(可选)上下文、(可选)资源约束即可;也可直接修改 interactive_guided_conversation.py 中的对应变量来快速试玩。
- 编辑现有插件:插件的全部实现位于 guided_conversation/plugins/ 目录。
- 编辑编排器:编排逻辑集中在 guided_conversation_agent.py。
- 复用插件:项目欢迎社区直接抽取
artifact与agenda两个插件用于既有工作——团队认为仅这两个插件本身就能提升其他 Agent 的目标遵循能力(goal-following)。
设计要点与适用前提小结
- 可靠性的来源是"代码"而非"提示词":产物字段校验由 Pydantic 强制执行,议程轮数由
_validate_agenda_update程序化校验,工具调用由validate_tool_calling校验并支持最多 2 次重试;LLM 只负责"思考"与"生成参数",这正是"用模型思考、用代码规划"的落地方式。 - 模型要求:框架依赖 function calling 与复杂推理,README 明确建议使用
gpt-4-1106-preview或gpt-4o以获得最佳质量与可靠性;交互脚本默认使用gpt-4o-2024-05-13部署。 - 环境前提:本示例是 Semantic Kernel 仓库下的演示项目,运行前需通过 poetry 安装依赖(含 git 引用方式安装的
semantic-kernel)、配置 Azure OpenAI 或 OpenAI 凭据,并满足 Python^3.10,<3.13的版本要求。 - 产物可作下游数据:对话结束时,
final_update保证产物字段与对话内容一致,产出的结构化 JSON(可通过to_json()导出)可直接用于生成报告、入库分析或作为后续流程的输入。
如需进一步动手验证,建议按顺序运行 01_guided_conversation_teaching.ipynb → 02_artifact.ipynb → 03_agenda.ipynb,并在 04_battle_of_the_agents.ipynb 中对比不同配置下 Agent 的行为差异。
【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考