Day8 学习日志:CO-STAR 与「Embedding 课前知识储备」——Prompt、工具链与可观测性

0 阅读7分钟

Day8 学习日志:CO-STAR 与「Embedding 课前知识储备」——Prompt、工具链与可观测性

📅 日期:2026-03-24
📌 定位:向量与检索正式开课前,把 输出可控工具调用闭环本地知识 mock长文 Map-Reduce运行日志 打牢。


一、CO-STAR:结构化 Prompt 的工程意义

在进入 Embedding / RAG 之前,要先承认一件事:检索再准,Prompt 写散了,模型照样会胡编或跑题。CO-STAR 把「长上下文里容易丢的约束」拆成固定维度,适合做成团队模板、评审清单。

维度含义和前端工作的类比
Context任务背景、业务边界需求背景、项目说明
Objective要完成的单一目标函数返回值 / 验收标准
Style文体与表述方式设计系统里的文案层级
Tone情绪与态度对用户说话的语气规范
Audience读者是谁用户画像、读者技术水平
Response输出形态(列表、Markdown、字段名)API 的 Response Schema

和 RAG 的关系:检索片段只是「动态 Context」的一部分;Objective + Response 决定模型是「严格引用材料」还是「自由发挥」。课前把 CO-STAR 写熟,后面接向量库时少一半扯皮。

工程落地:练习里把 CO-STAR 与「工具分流」写进 唯一一条 system 消息;百炼 Generation.call 若同时传非空的 prompt=,SDK 会再追加一条 user,容易打乱角色边界,故长约束应放在 messagesrole: system,而不是 prompt=

Gemini_Generated_Image_8907k48907k48907


二、工具调用:不是「注册了就智能」

这次练习里同时存在几类能力:列目录、读文本、拉监控快照。真实痛点是:模型不会自动知道该先读文档还是先查数,会受——用户措辞(是不是像「告警」)、工具在列表里的顺序、描述里有没有写清触发条件——共同影响。

几条可复用的工程经验:

  1. 把分流规则写进 System,用「必须 / 禁止 / 先后顺序」说话,比笼统「你可以调用工具」有效。
  2. 收窄「监控类」工具的描述:强调仅当用户明确要「当前 / 此刻」数值;流程、制度、联系人一律走读文档。
  3. 文档类工具放前、描述里写典型场景(SOP、报销、备份策略等),减轻「凡是告警就打监控」的路径依赖。
  4. 把「何时用哪个工具」也写进一份可被读取的说明(如 运维助手工具说明.md),让模型在犹豫时能读到「协议层」说明,而不是只靠参数猜。

三、多轮工具:一轮不够就必须循环

常见实现 bug 是:只执行第一轮 tool,把结果塞回上下文后又调一次模型,看到第二轮还是 tool_calls(例如要继续 read_local_file)却不再执行,直接回到读下一行用户输入——用户会感觉「没跑完」。

正确形态是 while / for 上限 内循环:每次请求 → 若有 tool_calls 就全部执行并 append → 再请求,直到某次响应没有 tool_calls、给出最终自然语言(或触达轮次上限并打日志)。这和后面做 Agent、ReAct 的状态机是同一类东西。 只设定了单轮functionCall 多轮调用tool

四、本地知识 mock:边界即安全

练习里知识被限制在固定根目录内:列举读取分离——先枚举相对路径,再按路径读文本。实现上要注意:

  • 路径规范化 + 禁止跳出根目录..、绝对路径),避免被提示词注入带偏。
  • 列表默认浅层、加条数上限,避免一次返回过大 JSON。
  • 大文件进日志时做截断,防止 JSONL 单条爆炸。

五、JSONL 运行日志:排障与复盘

自然日一个文件、每轮模型响应写一行 JSON,字段里带上:用户原话、第几轮、是否调工具、assistant 的 content、请求的 tool 列表、本地执行结果(可截断)。终端只打印有内容时的最终回答,减少刷屏;真要查「为什么没读某文件」,打开当天 JSONL 一行行看即可。

实现要点utils.append_practice_jsonl_line):写入后 flush + fsync,避免脚本未结束时在编辑器里看不到追加内容;对嵌套结构做 coerce + allow_nan=False,避免非标准键、NaN 等导致整行写失败;二级摘要 / Map-Reduce 的独立调用可记入同目录下的 YYYY-MM-DD_secondary.jsonl,与主对话日志分离,便于只看预处理链路。


六、长文本与 Map-Reduce(知识点 2)

问题read_local_file 若一次性返回极长正文,主对话上下文与费用都会吃紧;在还没接向量库前,需要 Map-Reduce 思想做预处理。

思路做法代价与风险
单次摘要长文交给「摘要专用」一次对话,再把摘要给主模型实现简单;摘要易丢条款号、联系人等细节
分块 Map + 合并 Reduce按固定字符窗口切块(可设 overlap 保留边界上下文),每块单独摘要,再开一轮把多块摘要合成总摘要,最后交给主模型调用次数多(N+1)、延迟高;切块若切断句子,靠 overlap 与合并提示缓解

练习代码中的对应关系

  • process_long_file(content, chunk_size, overlap):切块 → 逐块 _generation_plain_text(Map)→ 再合并(Reduce)。
  • 默认 chunk_size / overlap 可由模块常量或环境变量 MAP_REDUCE_CHUNK_SIZE / MAP_REDUCE_OVERLAP 调整;模型名可用 MAP_REDUCE_MODEL
  • read_local_file 结果超过 TOOL_OUTPUT_SUMMARY_THRESHOLD_CHARS(可用环境变量覆盖)时,主链路会走 Map-Reduce 预处理,再作为 tool 内容回到多轮对话。

需要持续考虑的工程点

  1. 健壮性:某块摘要或 Reduce 失败时,是否降级为「截断原文 / 拼接块摘要」,保证主流程不中断。
  2. 延迟与成本:对话轮次与 token 随块数上升,正式环境要权衡阈值(多长才触发 Map-Reduce)。
  3. 切块策略:当前按字符滑动窗口是学习用;生产可再换按段落、标题、token 等切分。 二级摘要的回答有部分内容缺失

七、System 模板与「静态 RAG 占位」的区分(知识点 3)

把 CO-STAR 抽成 constants.PROFESSIONAL_SYSTEM_TEMPLATE 时,若沿用「KNOWLEDGE BASE + {retrieved_context}」这类 经典 RAG 注入 写法,在本练习里会失真:事实并不在 system 里预填,而是 tool 消息动态返回。

本次修正方向

  • KNOWLEDGE BASE 段改为明确写清:可引用的事实仅来自对话中的 tool 返回(并点名 list_doc_files / read_local_file / get_current_status)。
  • 补回 Audience(受众) 占位,与 Role、Style、Tone 并列。
  • EXECUTION STEPS 改为「判类型 → 按工具分流调工具 → 以 tool 内容作答」,不再引导模型去交叉引用一块空的静态检索区
  • CO-STAR_Prompt.py 里删除与模板重复的冗长常量,单一数据源constants.py,避免两处改不全。

八、Prompt 变量占位符:Python 与模板习惯

场景规则注意
str.format(){name} 由关键字参数替换模板里若要输出字面量花括号,需写成 {{}}
RAG 注入有的流水线用 {retrieved_context} 在服务端替换后再发给模型tool 流 并存时,要在文案里说清「上下文从哪来」,避免模型盯着空的占位符
环境变量调参TOOL_OUTPUT_SUMMARY_THRESHOLD_CHARSCO_STAR_LOG_DIR适合测试阶段频繁改阈值而不改代码

九、今日小结与下一课

主题收获
CO-STAR长任务 Prompt 脚手架;与 RAG 的 Context 注入强相关;宜进 system 而非 SDK 的 prompt=
Tools描述 + 顺序 + System 分流,决定「像不像 Agent」
多轮必须闭环到 stop,不能只做单次 tool
知识边界根目录、列表、防穿越、日志截断
长文Map-Reduce 预处理 + 失败降级 + 阈值/环境变量可配
模板静态 RAG 占位 vs 工具返回事实,文案要与真实数据流一致

下一课预告:Embedding、向量空间直觉、与检索怎么接到 CO-STAR 的 Context 位上(届时可能是「向量检索结果注入」与「tool 读全文」的组合,而不是混用空占位)。