Hello-Agents 双智能体实战MeetingActionAgent 如何生成可追溯、可执行的会议纪要【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents本文以 Hello-Agents 共创项目 MeetingActionAgent 为主线完整讲解“提取 AgentMinutesAgent 审核 AgentReviewAgent”这一最小可用的双智能体协作模式如何定义 Pydantic 结构契约、如何用四次调用预算约束模型行为、如何用证据字段实现行动项的原文可追溯并给出从环境搭建到运行 main.ipynb 的完整操作步骤与示例输入输出。读完后你可以掌握在不使用工具调用、不依赖 RAG 的前提下用两个SimpleAgent顺序协作完成一段会议文字记录到结构化 JSON 与 Markdown 纪要的转换并通过审核循环抑制 LLM 的遗漏与编造。项目定位双 Agent 顺序协作的会议纪要流水线这是一个生产力工具类的双 Agent 小项目输入一段中文会议记录输出可追溯、可执行的会议纪要。项目的第一版有一条明确规则——原文没有的信息不猜未知负责人或日期会显示为“未提供”。整体流程分为四步MinutesAgent提取会议日期、摘要、决策、行动项和待确认问题ReviewAgent对照原文检查遗漏、编造和日期冲突审核未通过时系统最多修正一次最终生成结构化 JSON 和易读的 Markdown 会议纪要。会议文字记录 → MinutesAgent 生成结构化草稿 → ReviewAgent 对照原文审核 → 必要时修正并复核一次 → 保存 JSON 与 Markdown四个核心设计决策决定了这个项目的行为边界双 Agent 顺序协作提取与审核职责分离ReviewAgent 必须回到会议原文逐项核对不能因为文字通顺就判定通过Pydantic 数据校验模型返回的 JSON 必须通过BaseModel校验及时发现缺字段和错误类型有限重试整个流程共享四次模型调用预算不会无限循环证据追溯每个行动项保留对应原文evidence字段方便人工确认结果是否可靠。第一版刻意不使用工具调用普通 Python 代码负责读取、校验和保存文件Agent 只负责语言理解与审核。这一约束在 main.ipynb 中写得非常直接“第一版不使用工具调用”。项目结构与环境要求项目目录结构见 READMEHenry2513-MeetingActionAgent/ ├── README.md ├── requirements.txt ├── main.ipynb ├── .env.example ├── .gitignore ├── data/ │ ├── sample_meeting.txt │ └── edge_case_meeting.txt └── outputs/ ├── example_result.json └── example_minutes.md环境与依赖以 requirements.txt 为准依赖版本约束作用hello-agents0.2.9提供HelloAgentsLLM与SimpleAgentopenai1.109,2OpenAI-compatible 客户端pydantic2.12,3结构化数据校验python-dotenv1.2,2加载.env模型配置huggingface-hub1.20,2hello-agents 0.2.9在导入时需要此依赖jupyterlab/ipykernel4.4,5/6.30,8Notebook 运行环境环境要求为 Python 3.11以及一个可用的 OpenAI-compatible LLM API从提交 Notebook 的元数据看作者本地使用 Python 3.13 运行。数据模型用 Pydantic 定义三个结构契约整个项目的“接口”就是三个 Pydantic 模型定义在 main.ipynb 第 2 节。它们同时约束了模型输出的合法性边界# 表示从会议原文中提取的一条行动项。 class ActionItem(BaseModel): task: str Field(min_length1) owner: str | None None due_date_raw: str | None None priority: Literal[高, 中, 低, 未说明] 未说明 evidence: str Field(min_length1) # 表示最终输出的完整会议纪要及其审核状态。 class MeetingResult(BaseModel): title: str Field(min_length1) meeting_date: str | None None participants: list[str] Field(default_factorylist) summary: str Field(min_length1) decisions: list[str] Field(default_factorylist) action_items: list[ActionItem] Field(default_factorylist) open_questions: list[str] Field(default_factorylist) review_status: Literal[pending, passed, needs_manual_review] pending review_issues: list[str] Field(default_factorylist) # 表示 ReviewAgent 对纪要草稿的审核结论和问题。 class ReviewResult(BaseModel): passed: bool issues: list[str] Field(default_factorylist) missing_items: list[str] Field(default_factorylist) unsupported_items: list[str] Field(default_factorylist) revision_advice: list[str] Field(default_factorylist)几个字段设计值得注意due_date_raw保留原文日期字符串如“7月31日前”而非标准化日期这呼应了项目“未来计划”中“增加日期标准化工具同时保留原文日期用于核对”的思路——第一版不做日期归一化避免转换引入歧义priority用Literal枚举封闭取值非法优先级如“紧急”会被 Pydantic 直接拒绝Notebook 的离线自检就断言了这一点evidence要求min_length1从结构上强制“每个行动项必须有原文证据”落实证据追溯设计review_status的三态pending/passed/needs_manual_review是审核循环的结果出口修正一次后仍不通过的纪要宁可标记needs_manual_review交给人工也不强行输出“通过”。核心编排四次调用预算下的提取—审核—修正循环调用预算与结构化调用封装预算控制由CallBudget类实现上限 4 次任何 Agent 调用包括格式修复都计入预算class CallBudget: # 初始化模型调用次数上限。 def __init__(self, maximum: int 4) - None: self.maximum maximum self.used 0 # 计算剩余的模型调用次数。 property def remaining(self) - int: return self.maximum - self.used # 在次数限制内执行一次 Agent 调用。 def run(self, agent, prompt: str) - str: if self.remaining 0: raise RuntimeError(已达到四次模型调用上限) self.used 1 return agent.run(prompt)run_structured把“注入 JSON Schema → 调用 Agent → 解析校验 → 失败时修复一次”封装为一步# 调用 Agent 并将响应解析为指定的数据模型。 def run_structured( agent, prompt: str, model_type: type[BaseModel], budget: CallBudget, ) - BaseModel: schema json.dumps(model_type.model_json_schema(), ensure_asciiFalse) full_prompt f{prompt}\n\n必须遵循以下 JSON Schema\n{schema} raw_response budget.run(agent, full_prompt) try: return parse_model_response(raw_response, model_type) except ValueError as error: if budget.remaining 0: raise RuntimeError(fJSON 校验失败且没有剩余调用次数{error}) from error repair_prompt ( 上一次响应无法通过 JSON 校验。不要改变内容含义只修复格式。\n f校验错误{error}\n f原响应\n{raw_response}\n f目标 Schema\n{schema}\n 只返回修复后的 JSON。 ) repaired_response budget.run(agent, repair_prompt) return parse_model_response(repaired_response, model_type)这里有两个工程细节Schema 注入用model_json_schema()动态导出 Pydantic Schema 追加到用户提示词中模型与校验器天然对齐格式修复也算成本JSON 首次解析失败时允许一次“只修格式、不改语义”的修复请求但同样消耗预算。这保证了任何单步提取、审核、修正、复核最坏情况下不会突破总预算。JSON 解析本身也很防御——模型经常把 JSON 包在 Markdown 代码围栏里或前后加解释文字因此用“第一个{到最后一个}”截取最外层对象再交给json.loads# 从模型响应中截取并解析 JSON 对象。 def extract_json_object(text: str) - dict: start text.find({) end text.rfind(}) if start -1 or end -1 or end start: raise ValueError(模型响应中没有完整的 JSON 对象) return json.loads(text[start : end 1])两个 Agent 的提示词分工Agent 创建与提示词main.ipynb 第 4 节MINUTES_SYSTEM_PROMPT 你是严谨的中文会议纪要提取专家。 只使用会议原文明确支持的信息不得补充常识或猜测。 严格区分讨论、建议和已确认决策。 每个行动项必须保留一段原文证据未知负责人、会议日期或截止日期必须为 null。 只返回符合用户给定 Schema 的 JSON不要返回 Markdown 或额外解释。 REVIEW_SYSTEM_PROMPT 你是独立的会议纪要审核员。 必须逐项对照会议原文和纪要草稿检查遗漏、编造、模糊行动项和日期冲突。 不能因为文字通顺就判定通过也不能使用外部信息。 只返回符合用户给定 Schema 的 JSON不要返回 Markdown 或额外解释。# 创建 MinutesAgent 和 ReviewAgent。 def build_agents(): llm HelloAgentsLLM() minutes_agent SimpleAgent(nameMinutesAgent, llmllm, system_promptMINUTES_SYSTEM_PROMPT) review_agent SimpleAgent(nameReviewAgent, llmllm, system_promptREVIEW_SYSTEM_PROMPT) return minutes_agent, review_agent注意两个提示词的对称约束MinutesAgent 被禁止“补充常识或猜测”ReviewAgent 被禁止“使用外部信息”且“不能因为文字通顺就判定通过”——审核员的价值恰恰在于它独立于生成者的措辞逐项回到原文核对。完整分析流程的调用链analyze_meeting是编排核心从源码结构看其调用次数路径是确定的# 执行纪要提取、审核和必要时修正的完整流程。 def analyze_meeting(transcript: str) - tuple[MeetingResult, ReviewResult, int]: transcript validate_transcript(transcript) minutes_agent, review_agent build_agents() budget CallBudget(maximum4) draft_prompt f请从以下会议原文提取结构化纪要\n\n{transcript} draft run_structured(minutes_agent, draft_prompt, MeetingResult, budget) review run_structured(review_agent, make_review_prompt(transcript, draft), ReviewResult, budget) if review.passed: final_result draft.model_copy(update{review_status: passed, review_issues: []}) return final_result, review, budget.used issues review.issues review.missing_items review.unsupported_items if budget.remaining 2: final_result draft.model_copy( update{review_status: needs_manual_review, review_issues: issues} ) return final_result, review, budget.used revision_prompt ( 请根据审核意见修正纪要。仍然只能使用会议原文支持的信息。\n\n f【会议原文】\n{transcript}\n\n f【原草稿】\n{draft.model_dump_json(indent2)}\n\n f【审核意见】\n{review.model_dump_json(indent2)} ) revised run_structured(minutes_agent, revision_prompt, MeetingResult, budget) final_review run_structured(review_agent, make_review_prompt(transcript, revised), ReviewResult, budget) final_issues final_review.issues final_review.missing_items final_review.unsupported_items status passed if final_review.passed else needs_manual_review final_result revised.model_copy(update{review_status: status, review_issues: final_issues}) return final_result, final_review, budget.used调用路径可以归纳为场景模型调用最终状态首次审核通过提取 审核 2 次passed审核未通过且预算充足remaining ≥ 2提取 审核 修正 复核 4 次依复核结果而定审核未通过但剩余预算不足 2 次停止修正保留原草稿needs_manual_reviewbudget.remaining 2的守卫非常关键修正一次需要“修正 复核”两次调用若不够就果断降级为人工审核状态而不是让修正后的草稿失去复核。此外validate_transcript会在入口处拒绝少于 20 个字符的输入防止空输入进入模型。每次调用analyze_meeting都会通过build_agents()创建新的 Agent 实例Notebook 在“常见问题”一节明确说明这是为了避免多份会议的历史记录互相污染。Markdown 渲染结构化结果的确定性输出审核通过的纪要不再交给模型改写Markdown 由普通 Python 从MeetingResult确定性生成to_markdown空值统一渲染为“未提供”竖线与换行做转义以避免破坏表格# 将可空文本整理成适合 Markdown 表格的内容。 def markdown_cell(value: str | None) - str: if not value: return 未提供 return value.replace(|, \\|).replace(\n, )save_result则将结果同时落盘为outputs/{stem}.json与outputs/{stem}.md。快速开始1. 创建虚拟环境README 给出的原始命令为 Windows PowerShell 环境Linux/macOS 可换用source .venv/bin/activatepython -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install -r requirements.txt2. 配置模型复制 .env.example 为.env其完整字段为LLM_MODEL_ID LLM_API_KEY LLM_BASE_URL LLM_TIMEOUT60填写一个 OpenAI-compatible 模型服务即可例如LLM_MODEL_IDyour-model-id LLM_API_KEYyour-api-key LLM_BASE_URLhttps://your-provider.example/v1.env与运行产物outputs/meeting_result.json/outputs/meeting_result.md均已被 .gitignore 忽略禁止提交真实密钥。3. 运行 Notebookjupyter lab打开 main.ipynb确认内核使用当前项目的.venv然后从上到下运行。有一个必须注意的前提请从Henry2513-MeetingActionAgent项目目录启动 Jupyter。Notebook 首个代码单元用PROJECT_ROOT Path.cwd()定位项目根所有数据与输出路径都基于它不兼容其他工作目录。Notebook 的学习路线依次为加载环境与项目路径 → 定义会议纪要数据结构 → 解析并渲染结构化结果 → 创建两个 Agent → 编排提取、审核和一次修正 → 运行真实双 Agent 流程和离线自检。输入数据与输出格式默认输入是 UTF-8.txt文件也可以在 Notebook 中直接替换为粘贴的文本。data/目录提供两份对照样本sample_meeting.txt正常会议包含明确任务和负责人会议主题新用户注册功能迭代 会议日期2026-07-27 参会者林晓、周明、陈悦 林晓注册页面和表单校验由我负责7月31日前完成。 周明后端注册接口我来做截止8月3日。 陈悦我会在接口完成后执行联调测试但测试环境地址还没有确定。 周明决定邮箱验证码首版有效期设为5分钟。 林晓产品说明文档需要补充异常流程负责人会后确认。edge_case_meeting.txt边界会议包含模糊建议、日期冲突和缺失负责人会议主题移动端发布时间讨论 会议日期2026-07-27 参会者王宁、赵可、孙然 王宁可以考虑下个月上线但这只是一个初步想法。 赵可测试环境需要有人确认目前还没有负责人。 孙然会议前的记录写产品文档周三完成但今天讨论时又有人说周五完成。 王宁等测试环境确定后我们再决定最终发布时间。边界样本刻意制造了三类陷阱用“可以考虑/初步想法”表述的伪决策、无负责人的悬空任务、前后矛盾的截止日期。Notebook 末尾的练习单元格给出了参考脚手架confirmed_launch_decision: False、test_environment_owner: None、document_date_conflict: True要求先人工预测再让模型作答对比。输出包含三部分outputs/example_result.json 与 outputs/example_minutes.md 是正常会议的一次真实运行结果可直接用于理解格式。JSON 侧的核心结构节选{ title: 新用户注册功能迭代, meeting_date: 2026-07-27, summary: 团队明确了新用户注册功能的前后端分工、联调安排和验证码有效期同时记录了测试环境及产品文档负责人待确认的问题。, decisions: [邮箱验证码首版有效期设为5分钟], action_items: [ { task: 完成注册页面和表单校验, owner: 林晓, due_date_raw: 7月31日前, priority: 未说明, evidence: 林晓注册页面和表单校验由我负责7月31日前完成。 }, { task: 补充产品说明文档中的异常流程, owner: null, due_date_raw: null, priority: 未说明, evidence: 林晓产品说明文档需要补充异常流程负责人会后确认。 } ], open_questions: [ 联调测试的具体截止日期是什么, 测试环境地址何时能够确定 ], review_status: passed }注意第三、四条行动项负责人未确定时owner为null截止日期缺失时due_date_raw为null正是“原文没有的信息不猜”规则在数据层的落地而模糊点没有消失而是被转写进open_questions供会后跟进。对应的 Markdown 纪要 将空值渲染为“未提供”行动项以表格呈现每行都带“原文证据”列任务负责人截止日期原文优先级原文证据补充产品说明文档中的异常流程未提供未提供未说明林晓产品说明文档需要补充异常流程负责人会后确认。离线自检与运行记录Notebook 第 8 节包含 6 组不调用模型的离线自检提交时全部通过JSON 被json代码围栏包裹时parse_model_response仍能正确提取并解析示例结果的meeting_date校验2026-07-27最后一条行动项owner is None缺失可选字段处理空行动项列表时Markdown 渲染出占位行| 无 |validate_transcript拒绝过短输入ValueError非法优先级如“紧急”被 Pydantic 的Literal约束拒绝ValidationError。此外自检还断言to_markdown(expected_result)与仓库中提交的 example_minutes.md 逐字一致保证了示例输出与渲染函数的可复现性。README 披露的真实运行记录为提交前使用sample_meeting.txt完成一次真实运行共调用模型 2 次即首次审核直接通过路径最终审核状态passed提取 4 个行动项和 1 个已确认决策4 条行动项证据都能在会议原文中找到。作者明确说明本项目是入门规模的流程验证未做大规模准确率基准测试实际响应时间受所选模型与 API 服务状态影响。设计亮点、限制与后续计划项目亮点可以归纳为三点提取与审核分开执行ReviewAgent 必须回到会议原文逐项核对杜绝“通顺即通过”每个行动项保留原文证据结果可人工抽查可追溯性落到数据字段而非口头承诺调用次数有硬上限4 次、修正机会只有一次成本与行为都是可预期的。当前限制以 README 声明为准只处理文字记录不处理录音或实时会议不搜索互联网也不使用数据库、RAG、MCP 或长期记忆LLM 输出存在不确定性needs_manual_review的结果必须人工确认示例数据均为虚构内容不应输入敏感会议数据。未来计划增加日期标准化工具同时保留原文日期用于核对支持连续处理多份会议记录并分别保存结果。对想把这套模式迁移到其他“生成 审核”场景的开发者这个项目提供了三个可直接复用的模式用 Pydantic 模型同时充当 Schema 注入源与输出校验器、用显式调用预算把重试行为关进笼子、用null “未提供”显式表达未知而不是让模型猜。相关教程背景可参考 第四章 智能体经典范式构建 与 第七章 构建你的Agent框架本文引用的全部实现细节均在 main.ipynb 中可查。【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考