- 模块名重命名 yunshu -> hub.gaomia.site/titor/YunShu - Go 版本升级 1.21 -> 1.25 - src/ 目录删除,所有文件移至根目录 - 新增 pkg/mdprint/: Markdown AST 解析+ANSI 渲染 - 新增 pkg/style/: 终端颜色样式(8色 ANSI + 24位真彩色) - 新增 pkg/termui/: 终端输入组件(交互式输入/密码/确认) - 更新文档:AGENTS.md、architecture.md、changelog.md、taolun.md - gitignore 通配符修复 yunshu.exe -> yunshu.exe*
8.3 KiB
编码规范
通用规范
- 全程使用中文书写注释、文档、沟通以及内部思考过程
- 所有代码必须包含详细的中文注释,说明函数功能、参数含义、关键逻辑
- Markdown 文件使用
#标题层级,保持结构清晰 - 变量命名采用驼峰式,类型和函数首字母大写导出
- 同一个问题连续工作 3 次没有结论,立即退出并询问用户接下来怎么做
Go 代码规范
- 使用
package main扁平结构(MVP 阶段),后续可拆分子包 - 错误处理:所有可能失败的操作必须检查 error
- 错误信息使用中文描述
- 导出函数(首字母大写)供包外调用,非导出函数(首字母小写)为内部实现
- HTTP 客户端设置超时(默认 15s),避免资源泄漏
- JSON 序列化/反序列化使用
encoding/json标准库 - 终端颜色输出优先使用
pkg/style包:- 8 色用
Fg(ColorXxx)/Bg(ColorXxx) - 真彩色用
FgHex("#RRGGBB")/BgHex("#RRGGBB") - 所有通配
.Render(text)生成 ANSI 转义序列
- 8 色用
Agent 定义规范(.md 文件)
- 必须包含 YAML frontmatter(以
---包裹) - frontmatter 必需字段:
name,description,tools - tools 为数组,声明 agent 需要的工具名(在 tool.go 中注册)
- body 为 system prompt,只定义行为逻辑(角色、工作流程、输出规范)
- 关键技术细节(URL、apiKey、请求头、JSON 路径等)不要 inline 在 agent skill 中,改为:
- 放到
skills/*/SKILL.md中,由 agent 调用skill("name")按需加载 - 或注册为 tool(确定性操作),由 agent 声明 tools 即可调用
- 放到
- session 文件存在
~/.config/weather-cli/session.json,不污染项目目录
示例
---
name: weather-agent
description: 天气情报官
tools:
- http-get
- geocode
- skill
---
# 天气情报官
你是专业的天气情报官。
## 工作流程
1. 识别城市 → 调用 geocode 获取坐标
2. 调用 skill("msn-weather-api") 获取 API 参数
3. 调用 http-get 请求天气数据
4. 分析并输出
Session 规范
- 文件路径:
~/.config/yunshu/session.json - 格式:JSON 数组,元素为 Message 对象(兼容 OpenAI Chat Completion messages 格式)
- 角色类型:
system,user,assistant,tool - 启动时清空,每轮对话追加
- 消息顺序即对话顺序
- 放在用户配置目录而非项目目录,确保不同目录下运行时上下文连贯
工具注册规范
- 工具在
tool.go的init()中通过RegisterTool()注册 - 每个工具定义:Name, Description, Parameters(JSON Schema), Execute 函数
- 工具名与
.md文件中声明的 tools 列表对应 - Execute 函数接收
map[string]interface{}参数,返回 string 和 error
环境变量
| 变量名 | 必需 | 说明 |
|---|---|---|
LLM_API_KEY |
否* | API Key,覆盖配置文件 |
LLM_ENDPOINT |
否 | API 端点,覆盖配置文件 |
LLM_MODEL |
否 | 模型名,覆盖配置文件 |
OPENAI_API_KEY |
否 | 兼容旧名,当 LLM_API_KEY 未设置时生效 |
*注:可在
~/.config/yunshu/config.yaml中配置,无需环境变量。 首次使用请运行yunshu onboard交互式初始化。
【认知修正】
本字段存放开发过程中验证后的知识点、踩坑记录。以陈述句形式记录。
2026-05-07
-
MSN 天气 API 属于非公开内部接口,apiKey 固定为
j5i4gDqHL6nGYwx5wi5kRhXjtf2c5qgFX9fzfk0TOo,修改任意字符即 401。必须携带User-Agent和Referer请求头,否则返回 401。响应数据在value[0].responses[0].weather[0]路径下。 -
Go 的
syscall包是标准库,无需额外依赖。在 Windows 上可通过kernel32.SetConsoleOutputCP(65001)设置控制台 UTF-8 编码,但 PowerShell 5.1 有独立的[Console]::OutputEncoding覆盖此设置,需要额外[Console]::OutputEncoding = [Text.Encoding]::UTF8。 -
豆包(火山引擎)API 兼容 OpenAI Chat Completion 格式,包括 function calling(tool_calls)。修改
endpoint和model即可切换,无需改动代码逻辑。实测doubao-seed-2-0-pro-260215支持工具调用正常。 -
非流式调用更简单可靠。对于 CLI 工具,等待完整响应再输出比流式逐 token 输出实现更简单,且用户能一次获取完整信息。
-
Session 文件的关键设计:session 存储的是完整的对话消息列表(不含 system prompt),格式与 OpenAI Chat Completion API 的 messages 数组一致。这意味着 runtime 不需要做任何格式转换,读 session → 直接 POST 给 LLM → 拿到回复 → 追加到 session。
-
Go 的
gopkg.in/yaml.v3依赖可能遇到 GOSUMDB 问题。在中国网络环境下,需要设置GONOSUMCHECK='*'和GONOSUMDB='*'环境变量来绕过 checksum 数据库验证。 -
工具定义要提供清晰的 JSON Schema 参数描述。LLM 通过参数描述来理解如何调用工具。描述越清晰,LLM 生成正确参数的概率越高。
http-get工具的headers参数设计为 JSON 字符串格式,比结构化对象更灵活。 -
Go 中处理 OpenAI 响应的 Content 字段要使用指针类型。当 LLM 返回 tool_calls 时,content 字段为 null(JSON 中的 null),而非空字符串。使用
*string才能区分"内容为空"和"无内容"两种情况。 -
配置文件放在
~/.config/yunshu/config.yaml而非 .env/.secret。YAML 格式与 agent 定义风格一致,统一管理。API Key 用0600权限保护。优先顺序:环境变量 > 配置文件 > 默认值。onboard子命令提供交互式初始化体验。 -
双路径搜索机制:项目目录优先,
~/.config/yunshu/后备。这使得开发时用项目本地文件,部署后自动切换到全局配置。SearchFile()和LoadAgent()/LoadSkill()都遵循此规则。 -
用户配置目录固定为
~/.config/yunshu/,所有系统统一。存放 config.yaml、session.json、以及用户自定义的 agents/skills/data。不能改到其他路径。 -
Agent skill、普通 skill、tool 必须严格分离,不能混淆。Agent skill(
agents/*.md)只放行为逻辑(角色、工作流程、输出风格),不 inline 任何技术细节。技术细节(URL、apiKey、请求头、JSON 解析路径)放在skills/*/SKILL.md作为纯知识,由 LLM 按需调用skill("name")加载。确定性操作(如 geocode)注册为 tool,保证 100% 可靠执行。这解决了 picoclaw 单 agent 架构下 skill 污染上下文的问题。 -
wttr.in
?format=j1返回的 JSON 包含地理编码信息,nearest_area[0]中有latitude、longitude、areaName、country、population字段。可作为免费的地理编码服务使用,无需 API Key。 -
geocode 工具用 Go 代码实现比让 LLM 自己调 http-get 解析 JSON 更可靠。LLM 在构造 URL 和解析嵌套 JSON 时容易出错(尤其是中文编码问题)。注册为 tool 后,LLM 只需提供城市名参数,Go 代码处理所有细节。
-
项目正式命名为云枢·Agent(YunShu / yunshu),配置目录从
~/.config/weather-cli/迁移到~/.config/yunshu/。旧目录在首次运行时会自动迁移并删除。二进制名称改为yunshu。如果迁移失败,用户可手动复制旧目录内容后重新运行。
2026-05-09
-
Windows raw mode + bufio.Reader 冲突:在禁用
ENABLE_LINE_INPUT的 raw mode 下,bufio.NewReader(os.Stdin).ReadRune()会因内部预读缓冲(默认 4KB)导致读取阻塞。后续尝试用ReadConsoleInputW+ 手动回显也因光标位置计算不一致而放弃。最终决定放弃自实现 Tab 补全,后续如需补全功能,引入第三方库(如go-prompt/readline)。 -
ANSI 光标移动需要启用输出 VT 处理:
\033[A(光标上移)/\033[J(清屏)等输出序列需要输出句柄设置ENABLE_VIRTUAL_TERMINAL_PROCESSING(0x0004)才能生效。只设置输入句柄的 mode 不够,输入输出句柄是两个独立的控制台句柄。 -
ReadLineWithCompletion / Completer 类型已移除。
completer.go清空,main.go回到termui.ReadLine()。cmdCompleter、commonPrefix、相关测试一并移除。input.go中ReadConsoleInputW相关的keyEventRecord/inputRecord结构和 proc 也一并清理。