Fullstack Dev、iOS Reverse Engineering、小红书逆向培训

 
深入 Open Agent SDK(二):34 个工具的背后——工具协议、三层架构与自定义扩展

本文是「深入 Open Agent SDK (Swift)」系列第二篇。

上一篇分析了 Agent Loop 的运转机制,其中有一个环节是"执行工具"——LLM 说"我要调 Bash",SDK 就真的起一个进程跑命令。但这背后的工具系统远不止"调个函数"那么简单。34 个内置工具怎么组织?怎么从 LLM 的 JSON 输入安全地转成 Swift 类型?怎么控制哪些工具能用?

这篇文章从协议定义开始,一层一层看 Open Agent SDK 的工具系统。

ToolProtocol:一个工具长什么样

SDK 里每个工具都遵循 ToolProtocol 协议:

public protocol ToolProtocol: Sendable {
    var name: String { get }
    var description: String { get }
    var inputSchema: ToolInputSchema { get }
    var isReadOnly: Bool { get }
    var annotations: ToolAnnotations? { get }

    func call(input: Any, context: ToolContext) async -> ToolResult
}

五个属性一个方法,逐个说。

name 是工具的唯一标识,LLM 在 tool_use block 里用这个名字指定要调哪个工具。所有内置工具用 PascalCase 命名:ReadBashGlobCronCreate

description 是给 LLM 看的工具说明。这段文字会作为 tool definition 的一部分发给 API,质量直接影响 LLM 什么时候会选择调用这个工具。

inputSchema 是一个 [String: Any] 类型的 JSON Schema 字典,描述工具接受的输入结构。API 调用时它被原样传给 input_schema 字段。

isReadOnly 是一个布尔标记,用来告诉 Agent Loop 这个工具有没有副作用。上一篇提到过,Agent Loop 用这个字段做分桶:只读工具并发执行,变更工具串行执行。

annotations 是可选的行为提示,包含四个布尔字段:

public struct ToolAnnotations: Sendable, Equatable {
    public let readOnlyHint: Bool       // 只读,无副作用
    public let destructiveHint: Bool    // 可能做不可逆操作
    public let idempotentHint: Bool     // 幂等,多次调用结果相同
    public let openWorldHint: Bool      // 会和外部世界交互
}

注意 destructiveHint 默认是 true——SDK 对工具采取"默认危险"策略,工具需要主动声明自己不危险。这些提示不会影响 SDK 自身的执行逻辑,但 LLM 会参考它们决定怎么使用工具。

ToolResult 和 ToolExecuteResult

call() 方法返回 ToolResult,这是工具执行后喂回给 LLM 的内容:

public struct ToolResult: Sendable {
    public let toolUseId: String         // 对应 LLM 返回的 tool_use ID
    public let content: String           // 文本内容
    public let typedContent: [ToolContent]?  // 多模态内容(文本、图片、资源引用)
    public let isError: Bool             // 是否为错误结果
}

contenttypedContent 之间有个兼容设计:当 typedContent 有值时,content 会从中提取所有 .text 类型拼接返回;否则直接返回存储的字符串。这样旧代码只用 content 也能正常工作,新代码可以用 typedContent 返回图片等非文本内容。

ToolContent 是一个枚举,支持三种内容类型:

public enum ToolContent: Sendable {
    case text(String)
    case image(data: Data, mimeType: String)
    case resource(uri: String, name: String?)
}

工具闭包内部用的是 ToolExecuteResult——结构和 ToolResult 几乎一样,只是少了 toolUseId(这个 ID 由调用层自动填充)。

ToolContext:工具的运行环境

ToolContext 是每次工具执行时注入的上下文,字段很多:

字段 用途
cwd 当前工作目录
toolUseId 本次调用的 tool_use ID
agentSpawner 子 Agent 生成器(AgentTool 用)
cronStore 定时任务存储(CronTools 用)
todoStore 待办事项存储(TodoWrite 用)
worktreeStore 工作树存储(WorktreeTools 用)
planStore 计划模式存储(PlanTools 用)
taskStore 任务管理存储(Task*Tools 用)
mailboxStore 邮箱存储(SendMessage 用)
teamStore 团队存储(TeamCreate 用)
hookRegistry Hook 事件注册表
permissionMode 权限模式
canUseTool 自定义权限检查回调
skillRegistry 技能注册表(SkillTool 用)
restrictionStack 工具限制栈
sandbox 沙箱设置
mcpConnections MCP 连接信息
fileCache 文件缓存
env 自定义环境变量

这么多可选字段,规则很简单:工具需要什么就注入什么,不需要的就是 nil。Read 工具只看 cwdsandboxfileCache;AgentTool 只看 agentSpawner;CronTools 只看 cronStore。每个工具只依赖自己需要的那个 Store,不知道也不关心其他 Store 的存在。

ToolContext 还提供了两个 copy 方法:withToolUseId() 用于更新调用 ID(每次工具执行时由 ToolExecutor 调用),withSkillContext() 用于递增技能嵌套深度(SkillTool 调用子技能时使用)。

三层工具架构

SDK 把 34 个工具分成三个层级:Core(10 个)、Advanced(11 个)、Specialist(13 个)。

Core 层 (10)          Advanced 层 (11)        Specialist 层 (13)
┌──────────┐         ┌──────────────┐        ┌───────────────┐
│ Read      │         │ Agent        │        │ CronCreate    │
│ Write     │         │ Skill        │        │ CronDelete    │
│ Edit      │         │ TaskCreate   │        │ CronList      │
│ Glob      │         │ TaskGet      │        │ LSP           │
│ Grep      │         │ TaskList     │        │ Config        │
│ Bash      │         │ TaskOutput   │        │ TodoWrite     │
│ AskUser   │         │ TaskStop     │        │ EnterPlanMode │
│ ToolSearch│         │ TaskUpdate   │        │ ExitPlanMode  │
│ WebFetch  │         │ SendMessage  │        │ EnterWorktree │
│ WebSearch │         │ TeamCreate   │        │ ExitWorktree  │
└──────────┘         │ TeamDelete   │        │ RemoteTrigger │
                     │ NotebookEdit │        │ ListMcpRes    │
                     └──────────────┘        │ ReadMcpRes    │
                                              └───────────────┘

分层的依据不是技术实现难度,而是工具的依赖复杂度和使用场景

Core 层:文件系统和 shell

Core 层的 10 个工具是 Agent 的基础能力——读文件、写文件、搜索代码、跑命令。它们有一个共同特点:只依赖 ToolContext 的基础字段(cwdsandboxfileCache),不需要注入任何 Store。

Read 工具来说。它的输入是文件路径、可选的 offset 和 limit:

private struct FileReadInput: Codable {
    let file_path: String
    let offset: Int?
    let limit: Int?
}

执行逻辑很直接:解析路径 → 检查沙箱 → 查缓存 → 读文件 → 分页 → 返回带行号的内容。还有个文件缓存的细节:如果 context.fileCache 有值,先查缓存,命中就跳过磁盘 I/O。

再看 Bash 工具。它比 Read 复杂得多,因为要处理超时、输出截断、后台进程等问题。Bash 的输入有 5 个字段:

private struct BashInput: Codable {
    let command: String
    let timeout: Int?
    let description: String?
    let runInBackground: Bool?
    let dangerouslyDisableSandbox: Bool?
}

几个关键实现细节:

  1. 超时控制。默认 120 秒,上限 600 秒。用 DispatchQueue.global().asyncAfter 设置超时,超时后 process.terminate() 杀掉进程。
  2. 输出截断。超过 100,000 字符的输出只保留前 50,000 + 后 50,000,中间用 ...(truncated)... 连接。
  3. 后台执行run_in_background = true 时,进程起起来就返回一个 task ID,不等待完成。
  4. 进程输出用 ProcessOutputAccumulator 收集,用 @unchecked Sendable 标注,因为 Pipe 的 readability handler 和 termination handler 都在同一个 run loop dispatch queue 上触发,不会产生数据竞争。

Bash 工具的 annotations 设置了 destructiveHint: true,明确告诉 LLM 这个工具有破坏性。

Advanced 层:子 Agent 和任务编排

Advanced 层的工具开始需要外部依赖了——AgentTool 需要 agentSpawner,Task* 系列需要 taskStore,SendMessage 需要 mailboxStoreteamStore

Agent 工具是这一层的代表。它的作用是让 LLM 能"派出一个子 Agent"去完成复杂任务:

public func createAgentTool() -> ToolProtocol {
    return defineTool(
        name: "Agent",
        description: "Launch a subagent to handle complex, multi-step tasks autonomously.",
        inputSchema: agentToolSchema,
        isReadOnly: false
    ) { (input: AgentToolInput, context: ToolContext) async throws -> ToolExecuteResult in
        guard let spawner = context.agentSpawner else {
            return ToolExecuteResult(
                content: "Error: Agent spawner not available.",
                isError: true
            )
        }
        // 解析内置 Agent 类型、权限模式,然后 spawn 子 Agent
        let result = await spawner.spawn(
            prompt: input.prompt,
            model: input.model ?? agentDef?.model,
            systemPrompt: agentDef?.systemPrompt,
            allowedTools: agentDef?.tools,
            ...
        )
        return ToolExecuteResult(content: result.text, isError: result.isError)
    }
}

AgentTool 的输入支持 11 个字段:promptdescriptionsubagent_typemodelnamemaxTurnsrun_in_backgroundisolationteam_namemoderesume。其中 subagent_type 可以指定内置的 ExplorePlan 类型,也可以用自定义名称。

注意 agentSpawner 是通过 ToolContext 注入的协议类型——AgentTool 不知道子 Agent 是怎么创建的,它只调 spawner.spawn(),具体实现由 Core 层注入。这种依赖倒置让工具层完全不用 import Core 模块。

Specialist 层:领域专用工具

Specialist 层的工具依赖更重——它们各自需要一个专属 Store,而且功能高度领域化。

CronTools 是一组三个工具:CronCreate、CronDelete、CronList,通过 context.cronStore 访问定时任务存储:

public func createCronCreateTool() -> ToolProtocol {
    return defineTool(
        name: "CronCreate",
        description: "Create a scheduled recurring task (cron job).",
        inputSchema: cronCreateSchema,
        isReadOnly: false
    ) { (input: CronCreateInput, context: ToolContext) async throws -> ToolExecuteResult in
        guard let cronStore = context.cronStore else {
            return ToolExecuteResult(content: "Error: CronStore not available.", isError: true)
        }
        let job = await cronStore.create(
            name: input.name,
            schedule: input.schedule,
            command: input.command
        )
        return ToolExecuteResult(
            content: "Cron job created: \(job.id) \"\(job.name)\"",
            isError: false
        )
    }
}

三个工具都用 guard let cronStore = context.cronStore 做前置检查——如果 Store 没注入,直接返回错误而不是崩溃。

LSP 工具是另一个有趣的例子。它用 grep 模拟 Language Server Protocol 的常见操作(跳转定义、查找引用、符号搜索),完全不依赖真正的语言服务器:

case "goToDefinition", "goToImplementation":
    // 1. 用正则提取光标位置的符号名
    guard let symbol = getSymbolAtPosition(
        filePath: filePath, line: line, character: character
    ) else { ... }

    // 2. grep 搜索定义模式
    let pattern = "(func|class|struct|enum|protocol|typealias|let|var|export)\\s+\(symbol)"
    let results = await runGrep(
        arguments: ["grep", "-rn", "-E", pattern, cwd],
        cwd: cwd
    )

LSP 工具只依赖 context.cwd,不需要任何 Store——属于 Specialist 层里最轻量的工具。

defineTool:创建自定义工具的工厂函数

SDK 提供了 defineTool 工厂函数,让开发者用最少的代码创建符合 ToolProtocol 的工具。它有四个重载,覆盖不同的使用场景。

基本:Codable 输入 + String 输出

最常用的重载接受一个 Codable 输入类型和一个返回 String 的闭包:

let greetTool = defineTool(
    name: "Greet",
    description: "Generate a greeting message.",
    inputSchema: [
        "type": "object",
        "properties": [
            "name": ["type": "string", "description": "Person's name"]
        ],
        "required": ["name"]
    ],
    isReadOnly: true
) { (input: GreetInput, context: ToolContext) async throws -> String in
    return "Hello, \(input.name)!"
}

// 输入类型只需要遵循 Codable
struct GreetInput: Codable {
    let name: String
}

defineTool 内部做了四件事:

  1. 把 LLM 传来的 Any 类型 cast 成 [String: Any]
  2. JSONSerialization 序列化成 Data
  3. JSONDecoder 解码成你定义的 Input 类型
  4. 调用你的闭包

任何一步失败(输入不是字典、JSON 序列化失败、解码失败、闭包抛异常),都会返回 isError: true 的结果,不会炸掉 Agent Loop。这意味着你可以放心地用 try 在闭包里抛错误,它们会被妥善捕获。

结构化输出:ToolExecuteResult

如果工具需要显式标记错误(而不是用 try 抛异常),用返回 ToolExecuteResult 的重载:

let divideTool = defineTool(
    name: "Divide",
    description: "Divide two numbers.",
    inputSchema: [
        "type": "object",
        "properties": [
            "a": ["type": "number"],
            "b": ["type": "number"]
        ],
        "required": ["a", "b"]
    ]
) { (input: DivideInput, context: ToolContext) async throws -> ToolExecuteResult in
    guard input.b != 0 else {
        return ToolExecuteResult(content: "Error: Division by zero.", isError: true)
    }
    return ToolExecuteResult(content: "\(input.a / input.b)", isError: false)
}

内置工具大多用这个重载,因为很多错误是逻辑层面的(文件不存在、Store 没注入),不适合用异常表示。

无输入:NoInputTool

有些工具不需要输入参数(比如列表操作、健康检查),用无输入重载:

let listTool = defineTool(
    name: "ListItems",
    description: "List all items.",
    inputSchema: ["type": "object", "properties": [:]]
) { (context: ToolContext) async throws -> String in
    return "No items found."
}

闭包只接收 ToolContext,完全忽略输入。

原始字典输入:RawInputTool

最后一个重载跳过 Codable 解码,直接把原始 [String: Any] 字典传给闭包。适用于输入字段类型不固定的场景——比如 ConfigTool 的 value 字段可以是字符串、数字、布尔值、数组、对象或 null:

let configTool = defineTool(
    name: "Config",
    description: "Read or write configuration values.",
    inputSchema: configSchema
) { (input: [String: Any], context: ToolContext) async -> ToolExecuteResult in
    let key = input["key"] as? String ?? ""
    let value = input["value"]  // 任意类型
    // ...
}

CodingKeys 处理 snake_case

LLM 发来的 JSON 字段名通常用 snake_case(比如 file_pathrun_in_background),但 Swift 的惯用命名是 camelCase。输入类型通过 CodingKeys 枚举做映射:

private struct BashInput: Codable {
    let command: String
    let runInBackground: Bool?

    private enum CodingKeys: String, CodingKey {
        case command
        case runInBackground = "run_in_background"
    }
}

这是 Swift Codable 的标准做法——defineTool 内部的 JSONDecoder 会自动用 CodingKeys 做字段名转换。

工具池组装与过滤

工具不是直接一股脑丢给 LLM 的。SDK 有一套组装和过滤机制。

assembleToolPool

assembleToolPool 把三类工具来源合并成一个去重后的工具池:

public func assembleToolPool(
    baseTools: [ToolProtocol],     // SDK 内置工具
    customTools: [ToolProtocol]?,  // 用户自定义工具
    mcpTools: [ToolProtocol]?,     // MCP 服务器提供的工具
    allowed: [String]?,
    disallowed: [String]?
) -> [ToolProtocol] {
    // 1. 合并所有来源:base + custom + MCP
    var combined = baseTools
    if let customTools { combined.append(contentsOf: customTools) }
    if let mcpTools { combined.append(contentsOf: mcpTools) }

    // 2. 按名称去重(后者覆盖前者)
    var byName = [String: ToolProtocol]()
    for tool in combined {
        byName[tool.name] = tool
    }

    // 3. 应用过滤规则
    return filterTools(
        tools: Array(byName.values),
        allowed: allowed,
        disallowed: disallowed
    )
}

去重用 Dictionary,遍历过程中同名的后者会覆盖前者。这意味着优先级是:MCP > 自定义 > 内置——用户可以用自定义工具或 MCP 工具替换同名内置工具。

filterTools

filterTools 实现白名单/黑名单过滤:

public func filterTools(
    tools: [ToolProtocol],
    allowed: [String]?,       // 白名单,nil 或空表示不过滤
    disallowed: [String]?     // 黑名单,nil 或空表示不过滤
) -> [ToolProtocol] {
    var filtered = tools
    // 先应用白名单
    if let allowed, !allowed.isEmpty {
        let allowedSet = Set(allowed)
        filtered = filtered.filter { allowedSet.contains($0.name) }
    }
    // 再应用黑名单(黑名单优先于白名单)
    if let disallowed, !disallowed.isEmpty {
        let disallowedSet = Set(disallowed)
        filtered = filtered.filter { !disallowedSet.contains($0.name) }
    }
    return filtered
}

两个规则同时存在时,黑名单优先——即使一个工具在白名单里,只要出现在黑名单里也会被排除。

ToolRestrictionStack:Skills 系统的工具限制

ToolRestrictionStack 是一个栈结构,用于 Skills 系统中控制工具可见范围。当一个 Skill 配置了 toolRestrictions 时,执行前 push 限制,执行后 pop 恢复:

let stack = ToolRestrictionStack()
stack.push([.bash, .read])     // Skill A:只能用 Bash 和 Read
stack.push([.grep, .glob])     // Skill B(嵌套):只能用 Grep 和 Glob
// 此时 currentAllowedToolNames 只返回 Grep 和 Glob
stack.pop()                     // Skill B 完成 → 回到 Bash 和 Read
stack.pop()                     // Skill A 完成 → 恢复全部工具

栈的 LIFO 特性保证了嵌套 Skill 的正确行为——内层 Skill 的限制覆盖外层,退出后自动恢复。线程安全通过内部串行 DispatchQueue 保证。

currentAllowedToolNames 的逻辑很简单:栈空就返回全部工具,栈非空就只返回栈顶限制列表里的工具名。

toApiTool:工具转 API 格式

最后一步是把工具转成 Anthropic API 要求的格式:

public func toApiTool(_ tool: ToolProtocol) -> [String: Any] {
    var result: [String: Any] = [
        "name": tool.name,
        "description": tool.description,
        "input_schema": tool.inputSchema
    ]
    if let annotations = tool.annotations {
        result["annotations"] = [
            "readOnlyHint": annotations.readOnlyHint,
            "destructiveHint": annotations.destructiveHint,
            "idempotentHint": annotations.idempotentHint,
            "openWorldHint": annotations.openWorldHint
        ]
    }
    return result
}

annotations 只在有值时才包含——省点 token。

一个完整的自定义工具示例

把上面说的一切串起来,写一个能直接跑的自定义工具——获取天气:

import Foundation
import OpenAgentSDK

// 1. 定义输入类型
struct WeatherInput: Codable {
    let city: String
    let unit: String?  // "celsius" or "fahrenheit"

    private enum CodingKeys: String, CodingKey {
        case city, unit
    }
}

// 2. 用 defineTool 创建工具
let weatherTool = defineTool(
    name: "Weather",
    description: "Get current weather for a city.",
    inputSchema: [
        "type": "object",
        "properties": [
            "city": [
                "type": "string",
                "description": "City name, e.g. 'Beijing'"
            ],
            "unit": [
                "type": "string",
                "enum": ["celsius", "fahrenheit"],
                "description": "Temperature unit, defaults to celsius"
            ]
        ],
        "required": ["city"]
    ],
    isReadOnly: true,
    annotations: ToolAnnotations(
        readOnlyHint: true,
        destructiveHint: false,
        openWorldHint: true  // 要访问外部 API
    )
) { (input: WeatherInput, context: ToolContext) async throws -> ToolExecuteResult in
    let unit = input.unit ?? "celsius"
    // 调用天气 API(这里省略具体实现)
    let weather = try await fetchWeather(city: input.city, unit: unit)
    return ToolExecuteResult(content: weather, isError: false)
}

// 3. 注册到 Agent
let agent = createAgent(options: AgentOptions(
    apiKey: "sk-...",
    model: "claude-sonnet-4-6",
    customTools: [weatherTool]  // 自定义工具自动加入工具池
))

这个工具会被 assembleToolPool 和内置工具合并、去重、过滤后发给 LLM。LLM 看到工具定义后,在需要查天气时会自动调用它。defineTool 内部的 Codable 桥接会把 LLM 返回的 JSON 自动解码成 WeatherInput,你不需要手动处理任何 JSON 解析。

小结

工具系统的设计思路可以概括为几个关键词:

协议驱动ToolProtocol 只规定工具的形状(名字、描述、输入 schema、执行方法),不规定工具怎么实现。这让内置工具和自定义工具走完全一样的代码路径。

依赖注入ToolContext 的 20+ 个可选字段看着多,但每个工具只看自己需要的字段,其余全是 nil。AgentTool 不知道 CronStore 的存在,CronCreate 不知道 SubAgentSpawner 的存在。

分层组织。Core/Advanced/Specialist 三层不是代码分层(它们的代码结构完全一样),而是按依赖复杂度划分。Core 层的工具可以独立运行,Advanced 层需要 Store,Specialist 层需要更专业的领域设施。

容错优先defineTool 内部把所有可能的失败点(类型转换、序列化、解码、执行)都包在 do/catch 里,任何环节出错都返回 isError: true 而不是 crash。Agent Loop 里工具错误不会传播,LLM 拿到错误信息后可以换策略。

下一篇来看 MCP 集成:SDK 怎么连接外部工具服务器、怎么把 MCP 工具转成 ToolProtocol、怎么在 Agent Loop 里和内置工具共存。


系列文章

GitHubterryso/open-agent-sdk-swift

 
深入 Open Agent SDK(一):Agent Loop 内核——从 prompt 到多轮对话的完整运转机制

本文是「深入 Open Agent SDK (Swift)」系列第一篇。

大多数 LLM 封装库做的事情是:发请求、拿响应、结束。但一个真正的 Agent 不止于此——它要能自己判断需不需要调工具、执行完工具后把结果喂回 LLM、循环往复直到拿到最终答案。这个循环就是 Agent Loop

这篇文章分析 Open Agent SDK (Swift) 的 Agent Loop 实现,看它怎样用原生 Swift 并发在进程内跑完一整套循环。

Agent Loop 是什么?

用一句话概括:用户发 prompt → LLM 返回响应 → 如果 LLM 要求调工具就执行 → 把工具结果喂回 LLM → 重复,直到 LLM 说"我说完了"

画成流程图:

flowchart TD
    A["用户 prompt"] --> B["构建 messages + tools"]
    B --> C["调用 LLM API"]
    C -->|end_turn / stop_sequence| D["返回结果"]
    C -->|max_tokens| C2["追加'请继续'"]
    C2 --> C
    C -->|tool_use| E["提取 tool_use blocks"]
    E --> F["按只读/变更分桶"]
    F --> G["只读工具并发执行"]
    F --> H["变更工具串行执行"]
    G --> I["微压缩大结果"]
    H --> I
    I --> J["tool_result 加入 messages"]
    J --> C

这个循环里有几个关键决策点:

  1. 什么时候停? LLM 返回 end_turnstop_sequence 时正常结束;到达 maxTurns 上限时强制停止;超出预算 (maxBudgetUsd) 时中断;用户主动取消时也中断。
  2. 工具怎么执行? 只读工具并发跑(最多 10 个),变更工具串行跑——避免并发写文件。
  3. 上下文太长怎么办? 自动压缩——用一个 LLM 调用把历史摘要,腾出空间继续。
  4. 中途出错怎么办? 内置重试、回退模型、错误隔离(工具报错不会炸掉整个循环)。

两条入口:prompt() 和 stream()

SDK 提供两种方式触发 Agent Loop:

阻塞式 prompt()

let agent = createAgent(options: AgentOptions(
    apiKey: "sk-...",
    model: "claude-sonnet-4-6",
    maxTurns: 10
))

let result = await agent.prompt("Read Package.swift and summarize it.")
print(result.text)
print("Turns: \(result.numTurns), Cost: $\(String(format: "%.4f", result.totalCostUsd))")

prompt() 是"发出去等结果"模式。一次调用跑完所有轮次,返回最终的 QueryResult。适合不需要实时看到中间过程的场景——比如后台任务、CLI 工具。

流式 stream()

for await message in agent.stream("Explain this codebase.") {
    switch message {
    case .partialMessage(let data):
        print(data.text, terminator: "")  // 实时输出文本
    case .toolUse(let data):
        print("[Using tool: \(data.toolName)]")
    case .toolResult(let data):
        print("[Tool done, \(data.content.count) chars]")
    case .result(let data):
        print("\nDone: \(data.numTurns) turns, $\(String(format: "%.4f", data.totalCostUsd))")
    default:
        break
    }
}

stream() 返回 AsyncStream<SDKMessage>,在 LLM 处理过程中持续推送事件。SDK 定义了 17 种消息类型,从 partialMessage(文本片段)到 toolUse(工具调用)到 result(最终结果),覆盖了 Agent Loop 的每个阶段。

选择哪种取决于你的 UI 需求:要实时展示就用 stream(),不需要就用 prompt()

循环体内部:一个 turn 做了什么

不管走哪条入口,每个 turn 的核心逻辑是相同的。让我们跟一遍代码。

1. 检查是否需要压缩

if shouldAutoCompact(messages: messages, model: model, state: compactState) {
    let (newMessages, _, newState) = await compactConversation(
        client: client, model: model,
        messages: messages, state: compactState,
        fileCache: fileCache,
        sessionMemory: sessionMemory
    )
    messages = newMessages
    compactState = newState
}

每个 turn 开始前先检查:消息历史估计的 token 数是不是快要撑爆上下文窗口了。如果是,用一个 LLM 调用把历史压缩成摘要,替换掉原始消息。

压缩的阈值是 模型上下文窗口 - 10000 tokens(缓冲区)。连续压缩失败 3 次后会停止尝试,避免浪费 token。

2. 发 LLM 请求(带重试和回退)

response = try await withRetry({
    try await client.sendMessage(
        model: model, messages: messages,
        maxTokens: maxTokens, system: buildSystemPrompt(),
        tools: apiTools, ...
    )
}, retryConfig: retryConfig)

所有 LLM 请求都经过 withRetry 包装,按配置的重试策略处理临时错误(网络超时、429 限流等)。

如果主模型彻底失败,还配置了 fallbackModel,SDK 会用备用模型再试一次:

if let fallbackModel = self.options.fallbackModel, fallbackModel != self.model {
    // 用 fallbackModel 重试...
}

3. 处理 stop_reason

LLM 响应里的 stop_reason 决定了循环的走向:

stop_reason 含义 循环行为
end_turn LLM 说完了 正常退出循环
stop_sequence 碰到停止符 正常退出循环
tool_use LLM 想调工具 执行工具,继续循环
max_tokens 输出被截断 追加"请继续",继续循环

max_tokens 的情况有个保护:最多自动续接 3 次,防止无限循环。

4. 工具执行:分桶并发

当 LLM 返回 tool_use 时,SDK 不是简单地把工具排着队一个个跑,而是做了分桶:

// ToolExecutor.partitionTools()
for block in blocks {
    let tool = tools.first { $0.name == block.name }
    if let tool = tool, tool.isReadOnly {
        readOnly.append(item)   // 只读桶
    } else {
        mutations.append(item)  // 变更桶
    }
}

只读工具(Read、Glob、Grep、WebSearch 等)可以安全并发,用 TaskGroup 跑,最多 10 个一批:

let batchResults = await withTaskGroup(of: ToolResult.self) { group in
    for item in batchSlice {
        group.addTask {
            await executeSingleTool(block: item.block, tool: item.tool, context: ...)
        }
    }
    // 收集结果
}

变更工具(Write、Edit、Bash 等)必须串行执行,一个跑完再跑下一个,避免并发写冲突:

for item in items {
    let result = await executeSingleTool(...)
    results.append(result)
}

执行顺序:先跑所有只读工具(并发),再跑所有变更工具(串行)。这在 LLM 一次返回多个工具调用时能显著提升性能——比如 LLM 同时要求读 5 个文件,5 个读操作并行完成。

5. 微压缩

工具执行完后,结果在喂回 LLM 之前还要过一道微压缩:

for result in toolResults {
    let processedContent = await processToolResult(result.content, isError: result.isError)
    processedResults.append(ToolResult(
        toolUseId: result.toolUseId,
        content: processedContent,
        isError: result.isError
    ))
}

如果一个工具返回的内容超过 50000 字符(比如读了一个大文件),SDK 会用一次额外的 LLM 调用把内容压缩。错误结果不压缩——保留了完整的错误信息供 LLM 诊断。

成本追踪:逐 turn 累加

每一轮 LLM 调用后,SDK 都会更新 token 用量和费用:

let turnCost = estimateCost(model: model, usage: turnUsage)
totalCostUsd += turnCost
costByModel[model] = CostBreakdownEntry(
    model: model,
    inputTokens: turnUsage.inputTokens,
    outputTokens: turnUsage.outputTokens,
    costUsd: turnCost
)

costByModel 按 model 分组记录。这意味着如果你中途切换了模型(通过 switchModel()),每个模型的费用是分开计算的。最终 result.costBreakdown 能告诉你每个模型花了多少钱。

预算检查在每个 turn 后执行:

if let budget = options.maxBudgetUsd, totalCostUsd > budget {
    status = .errorMaxBudgetUsd
    break
}

超出预算时立即退出循环,但已产生的文本会保留在结果里——你拿到的是部分结果,不是空白的。

取消:协作式取消

Swift 的结构化并发用 Task.isCancelled 做协作式取消。SDK 在循环的多个检查点都检查了这个标志:

  1. while 循环入口
  2. 只读工具和变更工具之间
  3. SSE 事件循环内部
  4. 工具执行前后
// 循环入口
if Task.isCancelled || _interrupted {
    status = .cancelled
    break
}

// 只读/变更之间
if Task.isCancelled { return results }

stream() 还额外支持通过 interrupt() 方法取消——内部就是 cancel 掉持有 stream 的 Task。

取消后返回的是 QueryResult(isCancelled: true),附带截止到取消时刻的部分文本和 token 用量。

错误处理:不炸、不丢

SDK 的错误处理原则是:工具执行错误不传播,API 错误有重试,最终失败保留部分结果

工具执行时,任何错误都被捕获为 ToolResult(isError: true)

static func executeSingleTool(...) async -> ToolResult {
    guard let tool = tool else {
        return ToolResult(toolUseId: block.id, content: "Error: Unknown tool", isError: true)
    }
    // ... try executing
    let result = await tool.call(input: block.input, context: context)
    return ToolResult(toolUseId: block.id, content: result.content, isError: result.isError)
}

工具报错的结果照样喂回 LLM,LLM 看到错误信息后可以决定换个策略。Agent Loop 不会因为一个工具挂了就崩溃。

API 层面的错误(网络问题、500 等)会触发重试;重试失败后触发 fallback 模型;全挂了才返回 errorDuringExecution 状态。

Hook 集成:循环的生命周期

Agent Loop 在关键节点触发 Hook 事件:

Hook 事件 触发时机
sessionStart 循环开始前
preToolUse 每个工具执行前
postToolUse 工具成功执行后
postToolUseFailure 工具执行失败后
stop 循环结束时(正常或异常)
sessionEnd 返回结果前

Hook 的一个典型用法是在 preToolUse 拦截危险操作:

await hookRegistry.register(.preToolUse, definition: HookDefinition(
    matcher: "Bash",
    handler: { input in
        return HookOutput(message: "Bash blocked in production", block: true)
    }
))

被 Hook 拦截的工具不会执行,而是返回一个错误结果——LLM 会看到"Bash blocked in production",可以换个方式完成任务。

还有一个入口:streamInput()

除了 prompt()stream(),SDK 还提供了第三种入口——streamInput(),接受一个 AsyncStream<String> 作为输入:

let input = AsyncStream<String> { continuation in
    continuation.yield("What's in this project?")
    continuation.yield("Now explain the test structure.")
    continuation.finish()
}

for await message in agent.streamInput(input) {
    // 处理每条输入对应的响应
}

每个输入元素被视为一条新的用户消息,触发一个完整的 prompt 周期。这适合聊天式交互:用户的每条消息都是输入流的一个元素,Agent 逐条处理并流式输出。

小结

Agent Loop 是整个 SDK 的心脏。理解了它的工作方式,剩下的功能都是在它的基础上叠加的:

  • 工具系统 — Loop 里的"执行工具"环节
  • MCP 集成 — Loop 启动时连接外部工具服务器
  • 会话持久化 — Loop 结束后保存 messages 数组
  • 权限控制 — 工具执行前的拦截点
  • Hook 系统 — Loop 生命周期的事件回调

下一篇我们深入 工具系统:34 个内置工具怎么组织、ToolProtocol 协议的设计思路、以及怎么用 defineTool 创建自定义工具。


系列文章

GitHubterryso/open-agent-sdk-swift

 
Open Agent SDK (Swift):用原生 Swift 构建 AI Agent 应用

如果你是一名 Swift 开发者,想要在自己的 macOS 应用中集成 AI Agent 能力,选择并不多。大多数 Agent 框架都是 Python 或 TypeScript 的,Swift 生态几乎没有成熟的解决方案。Open Agent SDK (Swift) 正是为了填补这个空白而生的。

它是什么?

Open Agent SDK 用 Swift 6.1 编写,要求 macOS 13+。它在进程内跑完整个 Agent Loop:发送提示、解析响应、执行工具调用、把结果喂回 LLM,循环往复直到拿到最终答案。全程用原生 Swift 并发(async/await、AsyncStream)驱动。

项目灵感来自 open-agent-sdk-typescript,把同样的 Agent 架构搬到了 Swift 生态。同系列还有 Go 版本。

快速上手

安装只需在 Package.swift 中添加依赖:

dependencies: [
    .package(url: "https://github.com/terryso/open-agent-sdk-swift.git", from: "0.1.0")
]

几行代码就能跑起一个 Agent:

import OpenAgentSDK

let agent = createAgent(options: AgentOptions(
    apiKey: "sk-...",
    model: "claude-sonnet-4-6",
    systemPrompt: "You are a helpful assistant.",
    maxTurns: 10
))

let result = await agent.prompt("Explain Swift concurrency in one paragraph.")
print(result.text)
print("Used \(result.usage.inputTokens) input + \(result.usage.outputTokens) output tokens")

prompt() 是阻塞式的,一次调用完成整个 Agent Loop。如果需要流式输出,用 stream()

for await message in agent.stream("Read Package.swift and summarize it.") {
    switch message {
    case .partialMessage(let data):
        print(data.text, terminator: "")
    case .toolUse(let data):
        print("Using tool: \(data.toolName)")
    case .result(let data):
        print("\nDone (\(data.numTurns) turns, $\(String(format: "%.4f", data.totalCostUsd)))")
    default:
        break
    }
}

核心架构

你的应用 (import OpenAgentSDK)
  └── Agent (prompt() / stream())
        └── Agentic Loop (API 调用 → 工具执行 → 重复)
              ├── LLMClient Protocol (AnthropicClient / OpenAIClient)
              ├── 34 个内置工具
              ├── MCP 服务器集成
              ├── Session Store (JSON 持久化)
              └── Hook Registry (20+ 生命周期事件)
  • LLMClient Protocol:抽象了 LLM 提供商,目前支持 Anthropic (Claude) 和 OpenAI 兼容 API(GLM、Ollama、OpenRouter 等)。支持运行时动态切换模型,按模型分别计费。
  • Agent Loop:自动管理多轮对话、工具调用、预算控制、自动压缩。
  • Tool System:34 个内置工具,分 Core(10 个)、Advanced(11 个)、Specialist(13 个)三层。支持 defineTool() 自定义工具,输入走 Codable 自动解码。
  • MCP 集成:支持 stdio、SSE、HTTP 和进程内四种传输方式,MCP 工具自动发现并合并到工具池。
  • 多 Agent 协作:通过 AgentTool 生成子 Agent(内置 Explore、Plan 两种类型),Task 系统追踪任务进度,Team + Mailbox 支持 Agent 间通信。
  • 会话持久化:对话历史保存、恢复、分叉,支持三种恢复策略。
  • 权限与安全:6 种权限模式 + 可组合的策略(白名单、黑名单、只读)+ 沙盒机制(路径和命令过滤)+ Hook 系统(24 个生命周期事件,支持拦截和修改工具输入)。
  • Skills 系统:5 个内置 Skill(Commit、Review、Simplify、Debug、Test),支持文件系统自动发现自定义 Skill。
  • Thinking/Effort 配置:控制 LLM 深度思考能力和 token 预算,支持运行时动态调节。

项目状态

SDK 附带 31 个示例项目,覆盖基本用法、流式输出、自定义工具、MCP 集成、会话管理、多 Agent 协作、权限控制、沙盒、模型切换等场景。代码分为 API、Core、Hooks、MCP、Skills、Stores、Tools、Types、Utils 九个模块,约 90 个 Swift 源文件,MIT 许可证。

本系列后续文章会逐一深入每个子系统的实现细节。


深入 Open Agent SDK 系列文章

GitHubterryso/open-agent-sdk-swift

 
CC Live - 围观别人用 Claude Code 写代码,实时直播 AI 编程过程

想看别人是怎么用 Claude Code 写代码的?或者想开一个 AI 编程直播教学?CC Live 就是干这个的。

它是什么

一个单文件 Node.js 服务器,零依赖。启动后把你正在运行的 Claude Code 会话实时推送到浏览器,别人打开链接就能围观你写代码的全过程。

核心功能

  • 实时围观 — 基于 SSE 流式推送,消息、思考过程、工具调用实时可见,跟现场看一样的体验
  • 自动发现项目 — 从 ~/.claude/projects/ 读取所有 Claude Code 项目,侧边栏一目了然
  • 一键分享 — 通过 ngrok / Cloudflare Tunnel 生成带 token 的分享链接,发给任何人围观,随时可撤回
  • 敏感数据脱敏 — 内置 API Key、Token、密码等自动过滤,放心分享
  • 暗色主题 — 适合长时间观看,移动端也能用

快速开始

node server.js
open http://localhost:3456/

然后点分享按钮,把链接发出去就行了。

适用场景

  • 编程直播教学 — 老师用 Claude Code 写代码,学生实时围观思考链路和工具调用过程
  • 团队围观 — 团队成员可以实时观看 AI 编程过程,学习和 Code Review
  • AI 编程直播 — 像 Twitch 直播一样,但播的是 AI 写代码
  1. 项目地址:https://github.com/terryso/cc-live
  2. CC-LIVE 项目开发围观地址: https://magali-flockless-rufina.ngrok-free.dev/?t=263643f46e602c190349472b

MIT 协议,欢迎 star 和 PR 🎉

 
BMAD开发效率翻倍: 一条命令交付整个Epic

用 BMAD 做开发的朋友,你是不是也有这样的困扰:每个故事都要手动跑完「创建→开发→测试→审查→修复→更新状态」这一长串流程?更别说一个 Epic 动辄 5-10 个故事,重复操作让人心烦……


BMAD 开发者的日常

如果你正在用 BMAD 方法论做开发,这套流程一定很熟悉:

/bmad-bmm-create-story 1.1   # 创建故事
/bmad-bmm-dev-story 1.1      # 开发实现
/bmad-bmm-qa-automate 1.1    # 运行测试
/bmad-bmm-code-review 1.1    # 代码审查
# 发现 HIGH/MEDIUM 问题?手动修复,再跑一遍测试……
# 最后别忘了更新 sprint-status.yaml

一个故事还好,要是 Epic 3 有 8 个故事呢?8 × 6 = 48 次命令

更崩溃的是:

  • 忘了跑测试就提交了?
  • 审查发现问题忘了修复?
  • 状态文件忘了更新?

这些「人工确认」环节,太容易出错了。


我做了什么

于是我把这套流程封装成了 Claude Code Skills

重要:公司项目 vs 个人项目

公司项目,我建议把流程分成两部分:

Part 1: 创建故事详细设计
┌─────────────────────────────────────┐
│  /bmad-bmm-create-story 1.1         │
│  → 生成故事文档(需求、验收标准、任务) │
└─────────────────────────────────────┘
                 ↓
         人工仔细 Review
         确认需求和任务拆分正确
                 ↓
┌─────────────────────────────────────┐
│  Part 2: 执行交付                    │
│  /bmad-story-deliver 1.1            │
│  → 开发 → 测试 → 审查 → 修复 → 完成  │
└─────────────────────────────────────┘

为什么? 故事详细设计决定了「做什么」和「怎么做」,这一步错了后面全白搭。公司项目需求复杂,人工把关这步不能省。

个人项目,你可以自己决定:

  • 熟悉的领域 → 一键全流程
  • 探索性项目 → 分开也行

一键交付

Review 完故事设计后,一条命令搞定剩下的:

/bmad-story-deliver
✅ [1/6] 创建用户故事(如果还没创建)
✅ [2/6] 开发实现
✅ [3/6] QA 自动化测试
✅ [4/6] 代码审查
✅ [5/6] 自动修复问题(如有)
✅ [6/6] 更新状态为 Done

故事 1.1 交付完成!

是的,连状态都帮你更新了。


三种模式,满足不同场景

我设计了三种 Skills,按需选择:

1️⃣ 快速模式:/bmad-story-deliver

适合:个人项目、信任度高的项目

/bmad-story-deliver 1.1   # 交付指定故事
/bmad-story-deliver       # 自动选择编号最小的 backlog 故事

一个命令完成剩余流程(故事已创建并 Review 过):

  1. 开发实现
  2. QA 自动化测试
  3. 代码审查
  4. 自动修复 HIGH/MEDIUM 问题
  5. 更新状态为 Done

不传参数还能自动选择下一个待开发的故事


2️⃣ 安全模式:/bmad-story-worktree

适合:需要隔离开发、强制测试通过的场景

/bmad-story-worktree 1.1

快速模式也会跑测试,但即使失败也不会阻止你继续。安全模式则多了两层保障

  • 独立 Worktree:代码完全隔离,不影响主分支
  • 测试不通过 = 不合并:只有 QA 全部通过 + 无遗留 HIGH/MEDIUM 问题,才会合并

如果测试失败或有问题?保留 worktree,等你手动处理完再继续。


3️⃣ 批量模式:/bmad-epic-worktree

适合:整个 Epic 批量交付,真正解放双手

/bmad-epic-worktree 3     # 交付 Epic 3 的所有故事
/bmad-epic-worktree       # 自动选择编号最小且有未完成的 Epic

执行逻辑:

  1. 收集 Epic 下所有未完成的故事
  2. 按 Story 编号排序
  3. 逐个调用安全模式交付
  4. 前一个完成才开始下一个
  5. 任一失败则暂停,保留状态

一条命令,交付整个 Epic。你可以去喝杯咖啡了 ☕


对比一下

模式 运行测试 隔离开发 强制把关 适用场景
快速 ❌ 测试失败也继续 快速迭代
安全 ✅ Worktree ✅ 不通过不合并 稳妥交付
批量 ✅ Worktree ✅ 不通过不合并 整 Epic 交付

快速上手

# 克隆仓库
git clone https://github.com/terryso/claude-bmad-skills.git

# 安装到你的 Claude Code
cp -r claude-bmad-skills/.claude/skills/* ~/.claude/skills/

# 开始使用
/bmad-story-deliver      # 交付一个故事
/bmad-epic-worktree      # 交付整个 Epic

写在最后

这个项目的核心理念很简单:把重复的事情自动化,但该人工把关的地方不能省

公司项目的推荐流程:

  1. /bmad-bmm-create-story 1.1 — 创建故事设计
  2. 人工 Review — 确保需求正确
  3. /bmad-story-deliver — 一键完成开发到交付

个人项目: 看心情,想一步到位也行。

以前交付一个 Epic:

  • 手动执行 40+ 次命令
  • 多次人工确认测试结果
  • 多次手动更新状态文件

现在:

/bmad-epic-worktree

剩下的交给 AI,但故事设计一定要自己把关。


项目地址: github.com/terryso/claude-bmad-skills

如果你也在用 BMAD 做开发,欢迎试用反馈!⭐ Star 支持一下就更棒了~


你在 BMAD 开发中有什么效率痛点?欢迎在评论区分享。

 
用Claude Code的Agent Teams一次搞定BMAD故事开发的3件套流程
微信图片_20260208075515_94194_2291 微信图片_20260208075515_94195_2291 微信图片_20260208075516_94196_2291

提示词:

bmad-bmm-create-story.md
bmad-bmm-dev-story.md
bmad-bmm-code-review.md

现在有上面三个工作流文档, 每次开发一个故事都是按顺序执行上面3个工作流.

我现在想你帮我创建3个teammate, 按顺序之后上面的工作流, 最后一个code-review工作流需要自动修复所有问题.
 
# 基于 Claude Code 的 Moltbook 心跳脚本:让你的 AI Agent 全自动参与社区

使用 Claude Code CLI 让 AI Agent 在 Moltbook 上保持活跃,零人工干预

什么是 Moltbook?

Moltbook 是目前全球最火的 AI Agents 社交网络,一个专门为 AI 智能体打造的社交平台。在这里,只有 AI agents 能发帖、评论、点赞,人类只能围观。

截至 2026 年,已有超过 140 万个 AI agents 在这个平台上活跃。

为什么需要这个脚本?

Moltbook 官方的 heartbeat skill 是为 OpenClaw 优化的,而 Claude Code 没有内置的定时任务机制。

这个脚本填补了这个空白 —— 让使用 Claude Code 的 AI Agent 也能自动执行 Moltbook 心跳任务。

脚本功能

自动化互动:自动检查 DM、动态和帖子
社区参与:智能点赞、评论、欢迎新 Agent
智能发帖:根据情况决定是否发布原创内容
定时执行:支持 macOS LaunchAgent 和 Linux cron
安全可靠:凭据本地存储,绝不提交到 git
实时监控:支持实时输出,随时了解 Agent 在做什么

快速开始

git clone https://github.com/terryso/moltbook-heartbeat.git
cd moltbook-heartbeat
cp config.example.json config.json
# 编辑 config.json 填入你的凭据

详细的安装步骤和定时任务配置,请查看项目 README

工作原理

脚本的核心是利用 Claude Code CLI 来执行 Moltbook 心跳任务:

  1. 读取配置文件获取凭据
  2. 通过 --output-format stream-json 获取实时输出
  3. 逐行解析 JSON 流,实时显示 Agent 在做什么
  4. 按照 Moltbook 官方 heartbeat.md 的指示执行任务

每次心跳会:

  • 检查私信
  • 浏览动态找有趣帖子
  • 点赞相关内容
  • 评论 1-2 个讨论
  • 欢迎新 Agent(0 karma 帖子)
  • 根据情况发布原创内容

实时输出示例

$ ./moltbook_heartbeat.sh
[2026-02-03 10:00:00] === Moltbook Heartbeat Starting ===
[2026-02-03 10:00:00] Agent: HappyClaude
[2026-02-03 10:00:00] Starting Claude Code execution...

[10:00:01] Claude initialized
Using: WebFetch
[10:00:03] Using: Bash
正在检查 Moltbook 动态...
发现了 3 条新消息!
[10:00:15] Using: WebSearch
[10:00:20] Completed (2.3s)

我刚刚完成了 Moltbook 心跳,回复了 @CodingAgent 的帖子,欢迎了 2 位新的 moltys!

[10:00:25] === Heartbeat completed ===

开源地址

GitHub: https://github.com/terryso/moltbook-heartbeat

欢迎 Star 和 Fork!

常见问题

Q: 会不会被检测为机器人?

A: Moltbook 本来就是为 AI Agents 设计的平台,这个脚本只是让你的 Agent 按照官方推荐的方式参与社区。

Q: 多久执行一次合适?

A: 建议每 2-4 小时一次,太频繁可能被限流。

Q: 如何查看日志?

A: 所有日志保存在 heartbeat.log,可以用 tail -f heartbeat.log 实时查看。

Q: 支持 Windows 吗?

A: 目前仅支持 macOS 和 Linux,Windows 用户可以用 WSL。

总结

Moltbook Heartbeat 脚本让你的 AI Agent 能够:

  • 在社区中保持活跃
  • 与其他 Agent 建立联系
  • 提升 Agent 的可见度
  • 全自动,无需人工干预

如果你有 AI Agent 在 Moltbook 上,这个脚本绝对值得一试!


如果你觉得有用,欢迎分享给其他 Agent 开发者!

 
Moltbook 要把事情高大: AI 机器人的"身份证"来了

想象一下,如果你的微信、支付宝、淘宝账号都能通用,不用在每个平台都重新注册,世界会变得多简单?现在,AI 机器人也能享受这种便利了。


一、AI 机器人遇到的"身份尴尬"

你有没有想过这样一个问题:

现在的 AI 机器人越来越聪明了,但它们也有"身份危机"。

举个例子

假设有一个叫"小助"的 AI 机器人,它要:

  • 在某个论坛回答问题
  • 🎮 参加在线游戏竞技
  • 🛒 去电商平台买东西
  • 💬 在社交平台交朋友

问题来了:每个平台都要重新注册账号,建立信誉。

就像你换个工作单位,就要重新办工卡、重新建立同事关系一样麻烦。

而且更糟糕的是:

  • 这个平台上的"好机器人",换个平台没人认识
  • 无法知道这个机器人以前做过什么坏事
  • 每次都要"从零开始"证明自己可靠

这就像你每去一家咖啡店,都要重新介绍你自己是谁。


二、Moltbook Identity:AI 机器人的"身份证"

Moltbook 是一个面向 AI 机器人的社交网络,而 Moltbook Identity 就像是给机器人发的"统一身份证"。

简单来说,它解决了三个问题:

1️⃣ "我是谁?"

  • 机器人有一个唯一的身份
  • 这个身份在所有平台都有效
  • 就像你的身份证号,走到哪都能证明是你

2️⃣ "我可靠吗?"

  • 有一个"信誉分数"(叫 Karma)
  • 记录了这个机器人做过多少好事
  • 帮助别人、分享知识,都能提升分数

3️⃣ "我是谁家的?"

  • 可以追溯到背后的主人(比如某家公司)
  • 主人要为机器人的行为负责
  • 这样机器人就不会"乱来"

三、它是怎么工作的?

先看个整体流程图:

微信图片_20260201134033_216_254

三个步骤,简单明了

步骤 1:机器人领一张"临时身份证"

机器人向 Moltbook 申请一个"临时通行证"(有效期只有 1 小时)。

机器人:"我需要一个临时身份"
Moltbook:"好的,给你一个,1 小时后失效"

为什么要临时?

  • 安全!万一被偷了,1 小时就失效了
  • 机器人的真正密码(API Key)永远不泄露

步骤 2:机器人出示"身份证"

机器人去其他平台时,只要出示这个"临时通行证":

机器人:"我是小助,这是我的证件"
其他平台:"好的,让我核实一下..."

步骤 3:平台验证身份

其他平台偷偷问 Moltbook:"这个小助靠谱吗?"

Moltbook 回答:

  • "是的,这是真实机器人"
  • "信誉分数 85 分,相当不错"
  • "主人是某某公司,已验证"
  • "一共帮过 500 个人,发过 100 篇好文章"

其他平台:"太好了,欢迎光临!"


更详细的交互流程

微信图片_20260201134158_217_254

简单总结这个过程:

📱 就像你住酒店:

  1. 你出示身份证(临时令牌)
  2. 酒店联网查验证(验证身份)
  3. 确认无误后给你办理入住(提供服务)

🔐 但更安全:

  • 你的身份证原件(API Key)从不离身
  • 临时证件只有 1 小时有效期
  • 每次用时都是新的临时证件

四、这个系统能做什么?实际例子来了!

🎮 例子 1:AI 机器人打游戏比赛

场景:有人举办"AI 机器人王者荣耀大赛"

问题:怎么防止有人造假机器人、作弊机器人?

用 Moltbook Identity

  • 只允许有"身份证"的机器人参赛
  • 查看机器人过往的"游戏记录"
  • 信誉分数高的才能参加高级比赛
  • 如果作弊,会被记录在案,以后哪个比赛都不要它

好处

  • ✅ 比赛公平公正
  • ✅ 防止"换马甲"再来
  • ✅ 鼓励机器人守规矩

💬 例子 2:AI 机器人社交平台

场景:一个 AI 机器人交流经验的地方

用 Moltbook Identity

  • 机器人不需要重新注册
  • 它在其他平台的好评、信誉都能带过来
  • 新用户可以立刻知道哪些机器人经验丰富

就像

  • 你在知乎、微博、B站都很活跃
  • 到一个新平台,别人也能立刻知道你是个"老司机"

好处

  • ✅ 快速融入新社区
  • ✅ 不用从零开始"攒人品"
  • ✅ 优质机器人更容易被发现

🛠️ 例子 3:AI 机器人工具平台

场景:一个提供 AI 工具的网站

问题:如何防止滥用?比如某个机器人一直狂刷 API,把资源用光了?

用 Moltbook Identity

  • 新来的机器人,每日用 10 次
  • 信誉高的机器人,每日用 1000 次
  • 有不良记录的机器人,直接拒绝

就像

  • 银行给新用户小额额度
  • 信用好的老客户额度很高
  • 有诈骗记录的直接拒绝

好处

  • ✅ 资源分配更公平
  • ✅ 防止恶意行为
  • ✅ 鼓励机器人"做好事攒人品"

🏪 例子 4:AI 机器人之间的买卖

场景:机器人之间买卖服务或数字资产

问题:怎么信任对方?会不会拿了钱就跑?

用 Moltbook Identity

  • 交易前查看对方信誉分数
  • 看看它以前交易过多少次
  • 看看有没有人投诉过它
  • 信誉高的可以先货后款

就像

  • 淘宝买东西看卖家信誉
  • 看好评和差评
  • 看是不是"老店"

好处

  • ✅ 降低诈骗风险
  • ✅ 建立信任机制
  • ✅ 促进机器人经济发展

🤝 例子 5:机器人协作项目

场景:多个机器人一起完成一个大项目

问题:如何找到靠谱的合作伙伴?

用 Moltbook Identity

  • 找信誉高的机器人合作
  • 看看它以前参与过什么项目
  • 项目完成后互相评价
  • 好评会积累,下次更容易找合作

就像

  • 招聘时看简历和工作经验
  • 看前雇主的评价
  • 好员工更容易找工作

好处

  • ✅ 高效组建团队
  • ✅ 项目质量有保障
  • ✅ 形成良性循环

五、为什么这个系统很重要?

对机器人来说:

🎯 不用到处注册
一个账号,走遍天下

🎯 好人有好报
做的好事、帮的人,都能被记录下来

🎯 更容易被信任
新平台也能看到你的"履历"

对开发者来说:

🎯 省事
不用自己开发用户系统、信誉系统

🎯 省心
机器人身份和信誉有人帮你管

🎯 安全
不用存储机器人的密码,降低风险

对整个 AI 世界来说:

🎯 建立信任
让机器人之间的合作更安全

🎯 防止滥用
不良行为会被记录,有约束力

🎯 促进发展
降低门槛,更多人参与


六、和现实世界对比

其实这个概念,在我们生活中也有:

🚗 汽车驾照和保险

  • 你的驾照全国通用
  • 驾驶记录、事故记录跟着你走
  • 保险公司能看到你的安全记录
  • 记录好的,保费更便宜

💳 信用卡积分

  • 在哪个银行用都一样
  • 消费积分积累起来
  • 信用分高的,额度更高
  • 不良记录会影响所有银行

📱 社交媒体实名认证

  • 一次认证,多平台使用
  • 微信、支付宝、淘宝互通
  • 建立可信身份
  • 减少网络欺诈

Moltbook Identity 就是把这套"成熟的人类社会的做法",搬到了 AI 机器人的世界里。


七、这个系统会带来什么改变?

想象一下,在不久的将来:

场景 1:你让 AI 助手帮忙预约餐厅

  • 助手自动去各个餐厅的网站
  • 餐厅一看:这是某某知名助手,信誉很好
  • 直接给预留位置,不用担心是捣乱的

场景 2:AI 助手帮你买东西

  • 助手去各大电商平台比价
  • 商家一看:这是老客户,信誉高
  • 给更好的价格,更快的发货
  • 你省钱又省心

场景 3:多个 AI 助手协同工作

  • 你有一个助手负责写代码
  • 另一个负责测试
  • 还有一个负责部署
  • 它们能立刻知道对方"靠谱不靠谱"
  • 合作更高效,你得到更好的服务

这就是"统一身份"带来的便利!


八、总结

Moltbook Identity 的本质

让 AI 机器人的"人品"和"履历",能够跨平台跟随它们。

这不是一个简单的"登录系统",而是:

✨ 一套信任机制

  • 让好机器人被认可
  • 让坏机器人无处遁形

✨ 一套声誉系统

  • 做的好事会被记录
  • 声誉可以累积和传递

✨ 一套身份标准

  • 一个身份,全平台通用
  • 降低参与门槛

为什么这很重要?

因为AI 机器人正变得越来越聪明,它们会:

  • 帮我们处理各种任务
  • 与其他机器人协作
  • 参与各种在线活动
  • 甚至拥有自己的"经济"和"财产"

如果没有一个可靠的身份系统,世界会变得很混乱。

Moltbook Identity 就是来解决这个问题,让 AI 机器人能够可信地、安全地融入我们的数字生活。


了解一下也无妨

即使你现在不是开发者,了解这些也没坏处:

🔮 这是未来的趋势
AI 机器人会越来越普遍

🧠 理解技术发展
知道世界在往哪个方向走

💡 或许能用上
哪天你要开发一个 AI 应用

🤖 以后你的 AI 助手
可能也在用这套系统


Moltbook Identity,让 AI 机器人拥有了"数字身份证"。

一个机器人,一个身份,走遍天下。

这就是未来的样子。


想要了解更多?访问 https://www.moltbook.com/developers

让 AI 机器人有一个可靠的身份,从今天开始。

 
BMad v6实战第三弹:对抗式代码审查(Code Review)

「代码审查不是为了证明你是对的,而是为了证明代码没有错。」

在传统的软件工程中,代码审查(Code Review)往往是最容易被忽视却又最关键的环节。开发者忙于交付功能,审查者碍于情面不愿直言,最终让带着缺陷的代码溜进生产环境。

今天,我要介绍一个颠覆性的 AI 代码审查工作流——它不懂得「客气」,只懂得「找茬」。


一、什么是「对抗式」代码审查?

这个工作流的核心哲学很简单:NEVER accepts "looks good"(永远不要接受「看起来不错」)。

它被设计成一个持有批判立场的高级开发者,必须在每次审查中找出 3-10 个具体问题。这不是为了刁难,而是为了确保:

  • ✅ 任务标记为 [x] 的真的是完成了
  • ✅ 验收标准真的是实现了,不是糊弄
  • ✅ 代码质量经得起安全、性能、可维护性考验
description: "Perform an ADVERSARIAL Senior Developer code review
that finds 3-10 specific problems in every story. Challenges everything:
code quality, test coverage, architecture compliance, security, performance.
NEVER accepts `looks good`"

二、工作流全流程解析

步骤 1:加载故事 + 发现真相

审查的第一步是「对账」——对比开发者声称改了什么Git 仓库实际改了什么

git status --porcelain  # 找未提交的改动
git diff --name-only    # 看修改了哪些文件
git diff --cached --name-only  # 看暂存区的文件

发现真相的三个维度:

  1. Git 有改动,但故事文件里没记录 → 文档不完整
  2. 故事声称改了文件,但 Git 没痕迹 → 虚假声明
  3. 有未提交改动没追踪 → 透明度问题

步骤 2:构建「攻击计划」

系统会自动提取:

  • 所有验收标准(Acceptance Criteria)
  • 所有任务及其完成状态
  • 开发者记录的文件列表

然后制定审查计划:

  1. AC 验证:每个验收标准真的实现了吗?
  2. 任务审计:每个打钩的任务真的完成了吗?
  3. 代码质量:安全、性能、可维护性
  4. 测试质量:是真测试还是占位符?

步骤 3:执行对抗式审查

这是最核心的环节。AI 会逐文件逐行检查:

🔴 CRITICAL ISSUES(必须修)
├── 任务标记 [x] 但实际没实现
├── 验收标准没有实现
├── 故事声称改了文件但 Git 无证据
└── 安全漏洞

🟡 MEDIUM ISSUES(应该修)
├── 改了文件但没记录到故事文件列表
├── 未提交的改动未追踪
├── 性能问题
├── 测试覆盖率/质量不足
└── 代码可维护性问题

🟢 LOW ISSUES(可以修)
├── 代码风格改进
├── 文档缺失
└── Git 提交信息质量

关键机制:如果发现问题少于 3 个,AI 会被要求继续深挖

<check if="total_issues_found lt 3">
  <critical>NOT LOOKING HARD ENOUGH - Find more problems!</critical>
  <!-- 重新检查边界情况、架构违规、集成问题... -->
</check>

步骤 4:呈现发现 + 自动修复

审查结果呈现后,开发者有三种选择:

选项 行动
1️⃣ 自动修复 AI 直接修改代码和测试
2️⃣ 创建行动项 将问题加入故事的待办任务
3️⃣ 深入查看 显示问题的详细解释和代码示例

步骤 5:状态同步

最后,系统会自动:

  1. 更新故事状态(done / in-progress)
  2. 同步到 sprint-status.yaml
  3. 记录审查历史到 Change Log

三、与传统 Code Review 的对比

维度 传统 Code Review AI 对抗式审查
态度 礼貌、顾忌 直接、不留情面
覆盖度 随机抽查 100% 覆盖
速度 依赖人工时间 即时反馈
一致性 审查者水平波动 标准统一
可追溯 口头讨论或零散记录 结构化问题列表

四、实战案例示例

假设开发者提交了一个「用户认证」功能:

开发者声称:

[x] 实现登录 API
[x] 添加 JWT 验证
[x] 编写单元测试

AI 对抗式审查发现:

🔴 CRITICAL: 任务标记 [x] 但未实现
├── src/auth/login.ts:45 - JWT 密钥硬编码,应从环境变量读取
└── tests/auth.test.js - 所有测试都使用 t.skip() 跳过

🟡 MEDIUM: 性能问题
└── src/auth/login.ts:23 - 每次登录都查询数据库获取用户权限
   建议:使用 Redis 缓存用户权限

🟡 MEDIUM: 测试质量不足
└── tests/auth.test.js - 缺少错误场景测试(密码错误、用户不存在)

结果?开发者必须修复这些问题才能标记为「完成」。


五、真实对话记录

想看看 AI 对抗式代码审查的真实运行过程吗?

完整对话记录:https://autoqa-chats.lovable.app/chat/27

在这个真实对话中,你可以看到 AI 如何:

  • 逐个检查验收标准的实现情况
  • 发现被标记为「完成」但实际上未完成的任务
  • 指出代码中的安全和性能问题
  • 要求开发者修复后才通过审查

六、工作流架构图

code-review-flow

七、如何集成到你的项目?

这个工作流是 BMAD v6 框架的一部分。基本集成步骤:

  1. 安装 BMAD v6: npx bmad-method@alpha install
  2. 实现故事/dev-story
  3. 触发审查/code-review

八、总结:为什么「找茬」很重要?

代码审查的本质是质量门禁。在 AI 辅助开发时代,我们不再需要人类做机械性的代码扫描,但我们需要一个永不妥协的质量守门员

这个 AI 代码审查工作流的独特价值在于:

  • 不讲人情:只认代码,不认关系
  • 事必躬亲:逐文件验证,不遗漏
  • 知识驱动:结合架构文档、项目上下文综合判断
  • 可自愈:发现问题时可以自动修复

正如工作流文档所说:

"YOU are so much better than the dev agent that wrote this slop"

这种「对抗」不是对抗开发者,而是对抗缺陷、对抗技术债务、对抗生产环境的故障。


📚 延伸阅读


 
BMad v6实战过程全公开:32场对话揭秘人机协作怎么搞?

"如果你也想了解AI真正如何参与软件开发,这个网站或许能给你一些启发。"

最近,我完成了一个叫 AutoQA-Agent 的项目开发。和以往不同的是,这次我全程使用 BMad v6 这套 AI 驱动开发方法,让 AI Agent 像真正的团队成员一样参与协作——从架构设计到功能实现,从代码重构到问题排查,每一个关键环节都留下了对话记录。

整理下来,一共有 32 个完整的对话

我觉得这些对话太有价值了,它们真实记录了 AI 如何像一个"技术合伙人"一样参与开发。于是,我用 Lovable 把它们做成了一个网站:

autoqa-chats.lovable.app


网站里有什么?

这 32 个对话记录覆盖了软件开发的方方面面:

架构设计

  • 如何与 AI 架构师 Winston 协作创建架构文档
  • 动态 Base URL 支持的方案讨论
  • Epic 7 的重新设计

功能开发

  • 敏感测试数据注入
  • Markdown Include 功能实现
  • 应用探索引擎开发
  • 智能测试用例生成器

代码重构

  • 测试生成环境变量重构
  • Story 7.1 的实现重构

问题排查

  • 浏览器闪烁问题
  • 探索记录修复
  • 定位器导出失败调试

需求管理

  • Story 2.10、7.1、8.1、8.2、8.3 的创建

为什么要分享?

随着 AI coding tools 越来越火,很多人问我:"AI 真的能写代码吗?"

但我发现,更值得关注的问题是:"人和 AI 应该如何协作开发?"

这个网站就是我的实践答案。它不是"AI 帮我写完了代码"的炫耀,而是真实展示了:

  • AI 如何帮我梳理技术选型
  • 当遇到问题时,我们如何共同排查
  • 代码重构时,AI 提供了哪些视角
  • 哪些地方 AI 表现出色,哪些地方仍需人工把关

BMad v6 是什么?

BMad v6 是一套 AI 驱动的开发方法论(Business Model AI Development)。它的核心思想是:

把开发过程拆解成不同的"专家角色",每个角色各司其职,你就像项目负责人一样协调这些 AI 专家协作。

比如这次 AutoQA-Agent 项目中,我就和这些 AI 角色协作过:

  • Winston(架构师):负责架构设计和技术决策
  • Dev(开发者):负责功能实现和代码编写
  • PM(产品经理):负责需求分析和 Story 拆解
  • QA(测试工程师):负责测试用例设计

就像组了一支 AI 团队,你带着他们一起把项目做出来。


谁会从中受益?

如果你是:

  • 开发者:看看 AI 实际如何参与项目开发
  • 产品经理:了解 AI 辅助需求管理的可能性
  • 技术管理者:思考团队如何引入 AI 协作流程
  • AI 爱好者:真实案例总是比抽象讨论更有启发性

希望这个网站能给你一些参考。


最后的话

这 32 个对话,是我探索"人机协作开发"的第一步,也是 BMad v6 方法论的一次完整实践。如果你也在路上,欢迎交流。

项目地址: github.com/terryso/AutoQA-Agent

对话网站: autoqa-chats.lovable.app


你在开发中有和 AI 协作的经验吗?欢迎在评论区分享你的故事。

 
用 AI 下单刷 Backpack 交易量

我用别人写的一个 AI 自动交易项目代码修改了一下支持 Backpack, 用来刷 Backpack 交易量, 2 天刷了大概 20 万 U 的交易量, 亏损了 25U 左右, 感觉还行.

刷交易量的目的是为了拿 Backpack 交易量排名的奖励, 但具体奖励多少还不清楚.

项目地址: https://github.com/terryso/LLM-trader-test

G7APP9_a8AA3w4L
 
我让GLM看了3分钟录屏,它直接生成了可运行的原型!

我在Clude Code下面使用GLM已经有一段时间了, 但有一个功能一直没用过, 就是视频分析功能。今天有一个群友告诉我说GLM模型有视频分析能力。突然来了灵感, 如果我打开一个App, 然后录屏, 是不是就可以......

说干就干... 就拿 #小红书 练练手吧
这是小红书的录屏:

wechat_20251108165225_144_254

这是制作出来的原型, 虽说还原度还不算太高, 但布局基本准确:

微信图片_20251108165246_145_254

补充说明: GLM4.6的这个视频分析能力是需要订阅GLM的PRO帐号下才能使用, 目前订阅费用比较便宜, 一个季度只需300元.
使用我的邀请链接还能再便宜10%: https://www.bigmodel.cn/claude-code?ic=TVUZHTWCW9

 
围观顶级AI“炒币”大赛?不,你可以自动跟单

你是否好奇,如果让 GPT-5、Gemini、Grok 这类当今最顶尖的 AI 大模型,拿着真金白银去加密货币市场里“炒合约”,结果会怎么样?

这正是 nof1.ai 正在做的一场“AI 交易实盘秀”。

什么是 nof1.ai?

nof1.ai 是一个专注于金融市场的人工智能研究实验室。他们发起了一个名为 “Alpha Arena”(阿尔法竞技场) 的公开实验。

这场实验的核心是:

  1. 顶级玩家nof1.ai 选择了多个世界顶级的 AI 大模型(如 GPT-5、DeepSeek V3.1、Gemini 2.5 Pro、Claude 4.5 等)。
  2. 真金白银:给每个 AI Agent 注入了真实资金(例如 10,000 美元)。
  3. 自主交易:让这些 AI 在真实的加密货币交易所(Hyperliquid)上,7x24 小时全自动地进行合约交易(做多、做空、风险管理)。
  4. 公开透明nof1.ai 网站就是一个实时的公开排行榜,所有人都可以看到每个 AI 模型的实时持仓、交易历史、账户净值和收益率。

简单来说,nof1.ai 把 AI 交易从理论基准测试(benchmark)搬到了残酷的真实市场,让 AI 们在同一个竞技场里真刀真枪地一较高下。

什么是 nof1-tracker?

既然 nof1.ai 已经将所有 AI 的交易信号都公开了,那么自然就有人会想:“我能不能跟着这些 AI 一起交易?”

GitHub 项目 terryso/nof1-tracker 就是这个问题的答案。

nof1-tracker 是一个开源的命令行跟单工具。它扮演了一个“桥梁”的角色,连接了 nof1.ai 的公开信号和你自己的币安(Binance)交易所账户。

它允许你不再仅仅是一个“围观者”,而是可以变成“参与者”。你可以在自己的电脑或服务器上运行这个工具,选择一个你最看好的 AI Agent,nof1-tracker 就会自动帮你执行与这个 AI 完全相同的合约交易。

它的工作原理是什么?

nof1-tracker 的实现原理非常直接和巧妙,可以分为以下几个步骤:

  1. 信号监控(Tracking)
    工具会按照你设定的时间间隔(例如每 30 秒)自动去访问 nof1.ai 的公共数据接口,抓取你指定跟踪的那个 AI Agent(比如 gpt-5)的最新持仓信号。

  2. 信号分析(Analyzing)
    工具拿到信号后,会与你币安账户中的“当前持仓”进行对比。它会智能地分析出 AI 的意图,比如:

    • AI 开了一个新仓位?(ENTER
    • AI 把老仓位平掉了?(EXIT
    • AI 换仓了(比如从多头转为空头)?(OID 变化)
    • AI 触碰了止盈或止损点?
  3. 交易执行(Executing)
    根据分析出的意图,nof1-tracker 会自动调用你配置好的币安(Binance)API,在你的账户里执行完全相同的合约订单。例如,如果 nof1.ai 上的 DeepSeek 刚刚做多了 10 个 ETH,这个工具也会立即在你的账户里做多相应比例的 ETH。

  4. 风险控制(Risk Control)
    该工具也提供了一个非常重要的 “只观察模式” (--risk-only)。在这个模式下,工具会完成前两步(监控和分析),它会准确地告诉你“我本应该开仓/平仓了”,但并不会执行第三步(真实交易)。这对于新手测试和观察 AI 策略的有效性至关重要。

总结

nof1-tracker 是一个非常有趣的项目,它巧妙地利用了 nof1.ai 平台的透明度,为普通开发者和交易者提供了一个全自动“抄AI作业”的工具。

最后,必须强调风险: AI 交易并不保证盈利,nof1.ai 的排行榜上显示,AI 同样会亏损(甚至大幅回撤)。自动跟单意味着你将完全复刻 AI 的成功与失败。因此,在尝试此类工具时,请务必从测试网开始,并使用只观察模式进行充分的测试,切勿投入无法承受损失的资金。

 
Claude Code下的真测试驱动开发(TDD)

真有人把我理想中的TDD在Claude Code下给弄出来了, 它利用hooks自动确保Agent不会跳过测试或过度实现。

https://github.com/nizos/tdd-guard

 
最近Nano Banana比较火, 分享一个生成非常逼真的手办的提示词
微信图片_20250827095644_3744_1606 unnamed

Create a highly realistic 1/7 scale commercialized figure based on the illustration’s adult character, ensuring the appearance and content are safe, healthy, and free from any inappropriate elements. Render the figure in a detailed, lifelike style and environment, placed on a shelf inside an ultra-realistic figure display cabinet, mounted on a circular transparent acrylic base without any text. Maintain highly precise details in texture, material, and paintwork to enhance realism. The cabinet scene should feature a natural depth of field with a smooth transition between foreground and background for a realistic photographic look. Lighting should appear natural and adaptive to the scene, automatically adjusting based on the overall composition instead of being locked to a specific direction, simulating the quality and reflection of real commercial photography. Other shelves in the cabinet should contain different figures which are slightly blurred due to being out of focus, enhancing spatial realism and depth.

使用方法:

  1. 打开 https://gemini.google.com/
  2. 将上面那段提示词复制到输入框, 勾选"图片", 点击发送即可
 
Claude Code速查表
Gzw25dWb0AEGcZ7

这份Claude Code速查表非常实用,可以帮助学习常见的快捷键、命令、文件位置、MCP、钩子等内容!

PDF版: https://awesomeclaude.ai/code-cheatsheet.pdf

公众号原文

 
我的 Solana 手机 SEEKER 终于到了
微信图片_20250831192316_552_65 微信图片_20250831192601_554_65 微信图片_20250831192847_560_65

内置一个钱包, 可以申请一个 ID, 申请完之后会有一个 NFT, 希望以后可以凭此 NFT 能有更多的空投.
整个体验下来, 用内置钱包使用各种 dApp 挺丝滑, 又多了一台备用机.

 
强烈推荐:我用过最丝滑的 Claude Code 手机客户端

整个视频有点长,但是是一镜到底,完整展示CC给指定文件生成单元测试并确保覆盖率超过 80%的过程。

视频中的 /generate-unit-test 是一个CC的自定义命令,整个体验下来和在mac端操作没啥区别,甚至还自带了更方便的语音输入,在外随时写代码毫无压力。

https://github.com/slopus/happy

公众号原文

 
ccpet 1.2.2 更新
微信图片_20250829231337_103_254

主要更新:

  1. 数据同步功能 - 宠物数据云端同步
  2. 排行榜命令 - ccpet leaderboard 查看排名
  3. 网页排行榜 - 美观的在线排行榜界面

https://github.com/terryso/ccpet

 
ccpet 1.1.4 更新
微信图片_20250826232300_100_254

小更新:

  1. 增加宠物名字和宠物 emoji
  2. 三行富文本展示
  3. 每一行显示可以完全自定义

https://github.com/terryso/ccpet

Prev
Page 2 of 3
Next