118 lines
7.1 KiB
Markdown
118 lines
7.1 KiB
Markdown
|
|
# 编码规范
|
|||
|
|
|
|||
|
|
## 通用规范
|
|||
|
|
|
|||
|
|
- 全程使用中文书写注释、文档和沟通
|
|||
|
|
- 所有代码必须包含详细的中文注释,说明函数功能、参数含义、关键逻辑
|
|||
|
|
- Markdown 文件使用 `#` 标题层级,保持结构清晰
|
|||
|
|
- 变量命名采用驼峰式,类型和函数首字母大写导出
|
|||
|
|
- 同一个问题连续工作 3 次没有结论,立即退出并询问用户接下来怎么做
|
|||
|
|
|
|||
|
|
## Go 代码规范
|
|||
|
|
|
|||
|
|
- 使用 `package main` 扁平结构(MVP 阶段),后续可拆分子包
|
|||
|
|
- 错误处理:所有可能失败的操作必须检查 error
|
|||
|
|
- 错误信息使用中文描述
|
|||
|
|
- 导出函数(首字母大写)供包外调用,非导出函数(首字母小写)为内部实现
|
|||
|
|
- HTTP 客户端设置超时(默认 15s),避免资源泄漏
|
|||
|
|
- JSON 序列化/反序列化使用 `encoding/json` 标准库
|
|||
|
|
|
|||
|
|
## 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`,不污染项目目录
|
|||
|
|
|
|||
|
|
### 示例
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
---
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
1. **MSN 天气 API 属于非公开内部接口**,apiKey 固定为 `j5i4gDqHL6nGYwx5wi5kRhXjtf2c5qgFX9fzfk0TOo`,修改任意字符即 401。必须携带 `User-Agent` 和 `Referer` 请求头,否则返回 401。响应数据在 `value[0].responses[0].weather[0]` 路径下。
|
|||
|
|
|
|||
|
|
2. **Go 的 `syscall` 包是标准库,无需额外依赖**。在 Windows 上可通过 `kernel32.SetConsoleOutputCP(65001)` 设置控制台 UTF-8 编码,但 PowerShell 5.1 有独立的 `[Console]::OutputEncoding` 覆盖此设置,需要额外 `[Console]::OutputEncoding = [Text.Encoding]::UTF8`。
|
|||
|
|
|
|||
|
|
3. **豆包(火山引擎)API 兼容 OpenAI Chat Completion 格式**,包括 function calling(tool_calls)。修改 `endpoint` 和 `model` 即可切换,无需改动代码逻辑。实测 `doubao-seed-2-0-pro-260215` 支持工具调用正常。
|
|||
|
|
|
|||
|
|
4. **非流式调用更简单可靠**。对于 CLI 工具,等待完整响应再输出比流式逐 token 输出实现更简单,且用户能一次获取完整信息。
|
|||
|
|
|
|||
|
|
5. **Session 文件的关键设计**:session 存储的是完整的对话消息列表(不含 system prompt),格式与 OpenAI Chat Completion API 的 messages 数组一致。这意味着 runtime 不需要做任何格式转换,读 session → 直接 POST 给 LLM → 拿到回复 → 追加到 session。
|
|||
|
|
|
|||
|
|
6. **Go 的 `gopkg.in/yaml.v3` 依赖可能遇到 GOSUMDB 问题**。在中国网络环境下,需要设置 `GONOSUMCHECK='*'` 和 `GONOSUMDB='*'` 环境变量来绕过 checksum 数据库验证。
|
|||
|
|
|
|||
|
|
7. **工具定义要提供清晰的 JSON Schema 参数描述**。LLM 通过参数描述来理解如何调用工具。描述越清晰,LLM 生成正确参数的概率越高。`http-get` 工具的 `headers` 参数设计为 JSON 字符串格式,比结构化对象更灵活。
|
|||
|
|
|
|||
|
|
8. **Go 中处理 OpenAI 响应的 Content 字段要使用指针类型**。当 LLM 返回 tool_calls 时,content 字段为 null(JSON 中的 null),而非空字符串。使用 `*string` 才能区分"内容为空"和"无内容"两种情况。
|
|||
|
|
|
|||
|
|
9. **配置文件放在 `~/.config/yunshu/config.yaml` 而非 .env/.secret**。YAML 格式与 agent 定义风格一致,统一管理。API Key 用 `0600` 权限保护。优先顺序:环境变量 > 配置文件 > 默认值。`onboard` 子命令提供交互式初始化体验。
|
|||
|
|
|
|||
|
|
10. **双路径搜索机制**:项目目录优先,`~/.config/yunshu/` 后备。这使得开发时用项目本地文件,部署后自动切换到全局配置。`SearchFile()` 和 `LoadAgent()/LoadSkill()` 都遵循此规则。
|
|||
|
|
|
|||
|
|
11. **用户配置目录固定为 `~/.config/yunshu/`**,所有系统统一。存放 config.yaml、session.json、以及用户自定义的 agents/skills/data。不能改到其他路径。
|
|||
|
|
|
|||
|
|
12. **Agent skill、普通 skill、tool 必须严格分离,不能混淆**。Agent skill(`agents/*.md`)只放行为逻辑(角色、工作流程、输出风格),不 inline 任何技术细节。技术细节(URL、apiKey、请求头、JSON 解析路径)放在 `skills/*/SKILL.md` 作为纯知识,由 LLM 按需调用 `skill("name")` 加载。确定性操作(如 geocode)注册为 tool,保证 100% 可靠执行。这解决了 picoclaw 单 agent 架构下 skill 污染上下文的问题。
|
|||
|
|
|
|||
|
|
13. **wttr.in `?format=j1` 返回的 JSON 包含地理编码信息**,`nearest_area[0]` 中有 `latitude`、`longitude`、`areaName`、`country`、`population` 字段。可作为免费的地理编码服务使用,无需 API Key。
|
|||
|
|
|
|||
|
|
14. **geocode 工具用 Go 代码实现比让 LLM 自己调 http-get 解析 JSON 更可靠**。LLM 在构造 URL 和解析嵌套 JSON 时容易出错(尤其是中文编码问题)。注册为 tool 后,LLM 只需提供城市名参数,Go 代码处理所有细节。
|
|||
|
|
|
|||
|
|
15. **项目正式命名为云枢·Agent(YunShu / yunshu)**,配置目录从 `~/.config/weather-cli/` 迁移到 `~/.config/yunshu/`。旧目录在首次运行时会自动迁移并删除。二进制名称改为 `yunshu`。如果迁移失败,用户可手动复制旧目录内容后重新运行。
|