Blog

  • 贪吃蛇望清明


    贪吃蛇望清明

    Claude Code 香农渊源

    Claude Code 中的 Claude 为致敬克劳德·艾尔伍德·香农(Claude
    Elwood Shannon)。香农大多数学术成果在上世纪60年代前完成,然后,他
    就去玩别的去了,具体大概有

    ```
    ╔══════════════════════╗
    ║     机器老鼠闯迷宫    ║
    ║  ┌──────────────┐   ║
    ║  │  🐭 →  🧀     │   ║
    ║  │  │  ┌──┐     │   ║
    ║  │  └──┤  │     │   ║
    ║  │     └──┘     │   ║
    ║  └──────────────┘   ║
    ╚══════════════════════╝
    ```
    香农有篇论文,“介绍一个走迷宫的机器”,1951年。
    
    ```
    ╔══════════════════════╗
    ║        独轮车        ║
    ║      ╭─────╮        ║
    ║     ╱       ╲       ║
    ║    ╱    ○    ╲      ║
    ║   ╱           ╲     ║
    ║  ╱    🚲       ╲    ║
    ║ ╱               ╲   ║
    ║╱                 ╲  ║
    ╚══════════════════════╝
    ```
    
    狂热独轮车爱好者!
    
    ```
    ╔══════════════════════╗
    ║    三球抛接游戏      ║
    ║                      ║
    ║      ●               ║
    ║     ╱ ╲              ║
    ║    ●   ●             ║
    ║   ╱     ╲            ║
    ║  👨      👨          ║
    ║                      ║
    ╚══════════════════════╝
    ```
    
    最后一次表演在1985年的英国国际信息理论研讨会上。
    
    > 您无忧无虑的原因是什么?一位采访者在香农临终前采访他,我一生顺其
    > 自然,实用性不是我的主要目标。香农回答。
    

    输出超过最大词元数

    POST /v1/chat/completions { model: "", # 模型 messages: {...} # 上下文 tools: {...} # 工具调用 max_tokens: 4096 # Deepseek 默认4096 }

    API调用时候参数 max tokens 4096 是规定大语言模型的输出词元数,不要
    超过 4096 。大语言模型一般也是想到哪是哪,哪里会管这个。万一超过会
    有一个截断,结束原因设为 length

    json POST /v1/chat/completions { ... , max_tokens: 4096 } # 请求 { # 响应 id: "..." # ID choices: [{message: { role: "assistant", content: "...", # 返回消息, 可能截断 tool_calls: [...], # 工具调用,可能截断 }, finish_reason: "length"}, {...}], }

    Claude Code对finish_reason=length的应对

    愚人节 Claude Code 源码泄漏,使我们知道它大致的应对

    1. 第一次遇到finish_reason=length, 假设 1. max tokens=4096, 那就设 max tokens=8192,然后 2. 不做任何解释重试, 2. 8192 其实就是 deepseek 能设 max tokens最大值了, 3. 重试还遇到finish_reason=length, 那就 1. 记下截断的content, 并告诉模型 2. Output token limit hit. Resume directly — no apology, no recap of what you were doing. Pick up mid-thought...

    解释一下 no apology 。的确应该道歉,因为输出超过 max tokens,输出
    截断,可能截断在 content ,也可能截断在 tool calls。第一次重试的
    tokens 就等于浪费,用户需要为这些浪费的词元付费。不但如此,第二次又
    截断,而且这次 token 还更多,因为 max tokens 已经设到最大。按情理应
    该道歉。

    但Claude Code Harness说,不必愧疚,不要重述已经做的,从中间开始。

    ```
              ╭─────╮
             ╱  😔  ╲
            ╱  ┌─┐  ╲
           ╱   │ │   ╲
          ╱    └─┘    ╲
         ╱    /   \    ╲
        ╱    /     \    ╲
       ╱    ╱       ╲    ╲
      ╱    ╱         ╲    ╲
     ╱    ╱           ╲    ╲
    ╱    ╱             ╲    ╲
    ╲    ╲             ╱    ╱
     ╲    ╲           ╱    ╱
      ╲    ╲         ╱    ╱
       ╲    ╲       ╱    ╱
        ╲    \     /    ╱
         ╲    \   /    ╱
          ╲    ───    ╱
           ╲         ╱
            ╲       ╱
             ╲     ╱
              ╲   ╱
               ╲ ╱
                V
    ```
    

    Claude Code Harness

    我理解Claude Code Harness如下

    ```
        ╭───────╮
       ╱         ╲
      ╱    🐎     ╲
     ╱   ┌───┐    ╲
    ╱    │   │     ╲
    

    ╱ │ │ ╲
    ╱ └───┘ ╲
    ╱ / \ ╲
    ╱ / \ ╲
    ╲─────╱ ╲──────╱
    ╲ ╱ ╲ ╱
    ╲ ╱ ╲ ╱
    █ █
    █ 🚗 █
    █ ┌─────┐ █
    █ │ → │ █
    █ └─────┘ █
    █ █
    █████████████████
    “`

    贪吃蛇凯旋

    儿子说,贪吃蛇不能吃个没完,游戏么,要一级一级往上升才有意思,吃到
    100分比如,要有一个凯旋门出来,贪吃蛇可以撤离。

    Dscli 按设计做了。

    儿子说,这一级一级往上升AI也要帮忙才成,靠人谁吃得了100分?太难的游
    戏谁玩?

    Dscli 按设计做了。

    儿子说,要有音效,要有奖励,奖励要有动画。

    Dscli 按设计做,文件越来越大,终于碰到了 finish reason = length 问题

    Output token limit hit.

    Dscli Harness

    穷苦人出身,来自农村理工男,可惜 token 钱,解法与 Claude Code 不同。
    工具调用的设计

    ```
    ╔══════════════════════╗
    ║    🧠 LLM Agent      ║
    ╠══════════════════════╣
    ║  ┌──────────────┐   ║
    ║  │    Args      │←──║
    ║  └──────────────┘   ║
    ║         │           ║
    ║         ▼           ║
    ║  ┌──────────────┐   ║
    ║  │  Tool Call   │   ║
    ║  └──────────────┘   ║
    ║         │           ║
    ║         ▼           ║
    ║   ┌──┐ ┌──┐ ┌──┐   ║
    ║   │✅│ │💡│ │❌│   ║
    ║   └──┘ └──┘ └──┘   ║
    ╚══════════════════════╝
    ```
    
    在对(✅)错(❌)之间,加了个提示(💡)。把截断的内容修复,当成好
    的用,并提示大语言模型,输出超出max token 上限,内容截断已修复,无
    需道歉,但要感激我帮你改正错误,避免token浪费,下次输出从截断点开
    始,注意不要再次超过。
    
    千叮咛万嘱咐,帮AI完成大词元输出。这是我理解的Harness,好像本该如此。
    
  • 贪吃蛇野望

    儿子关心Dscli的开发进展,问我现在干什么。我其实没干什么。每次遇到不会
    解的问题,我就重构。现在我就在重构,给时间以时间,其实就是跟它耗,看谁
    耗得过谁。儿子认同但理解不同,他认为重构就是菜就多练。这就对了么,他说,
    高手也是一遍一遍练出来的,什么时候能写出贪吃蛇来才算本事。我从没让它写
    过贪吃蛇。我指望它能干正经活,解难题。为了这个野望它倒是留了一堆难题给
    我。我解不了只能重构,边重构边思考边学习,给自己时间跟它耗。但贪吃蛇这
    小玩意儿还不至于。

    儿子很快给出设计

    ┌───────────────────┐
    │ 贪吃蛇基础版      │
    │ ████              │
    │ ████     ●        │
    │                   │
    │ 得分: 50          │
    │ 长度: 4           │
    │                   │
    │ WASD: 移动        │
    │ 空格: 开始/暂停   │
    └───────────────────┘
    

    WASD能见他在游戏界功力,是有的。注,上图是Dscli补画,不是儿子或我画的,
    但主要意思在。

    Dscli 也行动起来,代码在
    https://gitcode.com/dscli/htmlgames 。

    我来为您创建一个贪吃蛇游戏。
    首先,让我分析一下需求:
    1. 绿色的蛇,吃红色的小球
    2. 蛇不断变长,变大
    3. 颜色由绿色向红色演变,最后变成红色
    

    蛇吃红球,由绿转红,是受《罗小黑战记》动画版比丢特性的影响。

    ✅ WriteFile 执行成功
    结果: 成功创建文件并写入 880 行内容
    
    太好了!我已经创建了一个完整的贪吃蛇游戏。
    

    我心说不对呀,怎么写游戏就能一口气干880行内容不卡壳,写文档400行断片儿。

    让我为您详细介绍一下这个游戏的特点:
     🎮 游戏特点
    1. *颜色演变系统*
    - 蛇初始为*绿色* (#00FF00)
    - 每吃一个食物,颜色向红色演变
    - 最终会变成*红
    色* (#FF0000)
    - 颜色条实时显示演变进度
    
    2. *成长系统*
    - 每吃一个食物,蛇的长度增加
    - 蛇的大小也会逐渐变大(从15px到最大30px)
    - 分数随食物数量增加
    
    3. *游戏机制*
    - 使用方向键或WASD控制
    - 支持移动端触摸控制
    - 游戏速度随分数增加而加快
    - 撞墙或撞到自己身体游戏结束
    
    4. *视觉效果*
    - 现代化UI设计,深色背景
    - 蛇身有发光效果
    - 食物有脉动动画
    - 蛇头有眼睛,会根据方向变化
    - 响应式设计,支持手机和平板
    
    5. *控制面板*
    - 实时显示分数、长度、大小和颜色值
    - 开始/暂停/重置按钮
    - 游戏说明面板
    - 游戏结束界面
    

    看着不错。儿子打开后发现只有一个绿点,代表蛇。豆子没有。儿子没料到这么快,因此有些小心翼翼,试探着说

    蛇是一个绿色小球,没有红色小球可吃,蛇永远是个绿色小球,无法变长变大。这是你故意设计的吗?
    

    Dscli倒是也不装

    您说得对!我发现了一个严重的问题。
    
    让我检查一下代码逻辑,确实存在食物生成和碰撞检测的问题。
    

    接着忙活,有10多分钟,期间儿子去玩蛋仔派对,我审视重构。儿子提出让
    Dscli写个符合他心意的蛋仔派对,被我拒绝。就算我重构完,所有难题解决,
    恐怕Dscli也写不了蛋仔派对这么伟大的游戏。

    现在游戏应该完全按照您的要求工作了:
    
    绿色的蛇吃红色小球,不断变长变大,颜色由绿色向红色演变!
    
    ⏱️ 13.2m 💰 CNY 0.83 💳 CNY 360.03
    

    用了13分12秒的时间,花了我8角3分钱,才解了这
    么个基础问题。这次是可以玩的。但由于自己菜的原因,玩不了一会蛇就撞死了。
    儿子说要加个作弊键。按一下A就让蛇自己找豆子吃。我说不好吧,不教它好,
    应该叫AI自主系统

    请加一个按键a,按了后,蛇自动吃豆子,按b取消自动吃豆子,再按a继续自动吃,再按b取消...
    

    看儿子要不停描述下去,我制止了他

    现在我来添加自动吃豆子功能。
    
    我需要:
    
    1. 在游戏状态中添加自动模式标志
    2. 添加A*路径查找算法或简单的自动导航算法
    3. 修改键盘控制,添加A键和B键的处理
    4. 在游戏循环中根据自动模式决定移动方向
    5. 更新UI显示自动模式状态
    

    考虑还算全面。A、B键是参考游戏手柄。但游戏手柄和键盘不同。A键和WSAD移
    动键有冲突的。我想到这层,坐看Dscli笑话。Dscli有用户插话机制,我可以在
    他埋头实现的时候提醒它。但我在想着我的重构,想着返回值JSON截断,也想看
    它出丑

    ✅WriteFile 执行成功
    
    结果: 成功创建文件并写入 863 行内容完美!
    
    我已经成功创建了带有自动吃豆子功能的贪吃蛇游戏。
    

    又一口气863行的内容!这写起游戏,就是比写文档开心呢!

    让我为您详细介绍新增的功能:
    
    🎮 新增功能:自动吃豆子模式
    
    *核心功能*
    1. *按A键开启自动模式* - 蛇会自动寻找并吃掉红色豆子
    2. *按B键关闭自动模式* - 恢复手动控制
    3. *智能路径规划* - 使用BFS算法寻找最短路径
    4. *安全避障* - 自动避开墙壁和自己的身体
    

    为了这么个作弊的功能,竟然开启广度优先算法去寻找。

    *键盘控制说明*​ 
    | 按键    | 功能                      |
    |---------+----------------------------|
    | ​*A*​      |开启自动吃豆子模式         |
    | ​*B*​      | 关闭自动模式,恢复手动控制 |
    |​ *方向键*​ | 手动控制蛇的移动           |
    | ​*WASD*​   | 手动控制蛇的移动(备用)   |
    | ​*空格键*​ | 开始/暂停游戏              |
    
    ​*技术亮点*​
    1. ​*完整的BFS实现*​ - 真正的路径查找算法
    2. ​*防碰撞检测*​ - 确保AI不会自杀
    3. ​*状态管理*​ - 清晰的状态切换逻辑
    4. ​*用户反馈*​ - 丰富的视觉和文本反馈
    5. ​*错误处理*​ - 处理各种边界情况
    
    这个版本完全满足了您的要求:
    
    按A键自动吃豆子,按B键取消自动模式,可以反复切换!
    
    ⏱️ 4.6m  💰 CNY 0.18  💳 CNY 357.80
    
    

    这次用了4分36秒,花了我1角8分实现。路径寻找算法是工作的。它大部分注意力集中于此,因此忽略的A键与WASD键的冲突。儿子抓到把柄按键

    A与WASD中的A冲突,可以把A换成C,这样就不冲突了
    

    Dscli也意识到

    您说得对!
    
    WASD中的A键确实与自动模式的A键冲突。
    
    让我将自动模式的触发键从A改为C,这样就不会冲突了。
    
    🔄 正在执行 WriteFile...
    → 创建文件"snake_auto_eat_fixed.html" 并写入 993 行内容
    
    ✅ WriteFile 执行成功   
    结果: 成功创建文件并写入 993 行内容
    

    又是一口气993行内容。真是气死人那。

    完美!我已经成功修复了按键冲突问题。
    
    现在让我为您总结一下更改:
    🔧 主要更改​
    
    *按键重新映射*
    ​|--------+--------+--------------------------|
    | ​*A*​    | ​*C*​     | 开启自动吃豆子模式       |
    | ​*B*​     | ​*B*​     | 关闭自动模式(保持不变) |
    
    ​*解决冲突*​
    1. ​*WASD中的A键*​:现在只用于向左移动(手动模式下)
    2. ​*C键*​:专门用于开启自动模式,不与任何移动键冲突
    3. ​*B键*​:保持不变,用于关闭自动模式
    
    ​*增强的用户界面*​ 
    
    1. ​*模式指示器*​
    - 顶部添加了醒目的模式指示器
    - 🎮 手动控制模式:绿色边框和图标
    - 🤖 自动控制模式:蓝色边框和机器人图标
    
    2. ​*按键图例*​
    - 添加了彩色按键图例,清晰显示各按键功能
    - 手动控制键:绿色背景
    - 自动控制键:蓝色背景
    - 功能键:灰色背景
    
    3. ​*视觉反馈增强*​
    - 自动模式下蛇头变为蓝色
    - 自动模式下蛇眼睛变为金色且更大
    - AI决策显示在画布上
    - 状态面板实时更新
    
    ​*改进的键盘处理逻辑*​ 
    
    #+begin_src javascript
    
    // 手动控制键(仅在非自动模式下有效)
    if (!game.autoMode) { 
      // 处理WASD和方向键
    } 
    
    // 功能键(任何模式下都有效)
    switch (key) {   
    case 'c': // 开启自动模式    
    case 'b': // 关闭自动模式    
    case ' ': //开始/暂停}
    #+end_src 
    
    ​*AI算法优化*​
    1. ​*路径长度显示*​:显示找到的路径长度
    2. ​*更好的决策反馈*​:更详细的AI决策说明
    3. ​*实时路径重计算*​:每次吃到食物后重新计算最优路径
    
    🎮 操作说明更新​
    
    *手动控制模式*
    ​- 使用 ​*WASD*​ 或 ​*方向键*​ 控制蛇的移动
    - 按 ​*空格键*​ 开始/暂停游戏
    - 按 ​*C键*​ 切换到自动模式
    
    ​*自动控制模式*​
    - 蛇会自动寻找并吃掉红色豆子
    - 使用BFS算法计算最短路径
    - 自动避开墙壁和自己的身体
    - 按 ​*B键*​ 切换回手动模式​
    
    *模式切换*​
    - ​*C键*​:手动 → 自动
    - ​*B键*​:自动 → 手动
    - 可以随时切换,游戏不会中断
    
    现在游戏完全解决了按键冲突问题,C键用于开启自动模式,B键用于关闭自动模式,可以反
    复切换使用!
    
    ⏱️ 5.2m  💰 CNY 0.11  💳 CNY 357.56
    

    还可以。儿子玩的开心。BFS算法比人玩得好多了,通常500分以上。我俩最多玩到80分。最后附上架构设计图(不是我画的,是Dscli画的)

    ┌───────────────────┐
    │ 智能AI版          │
    │ 🔵███             │
    │ ████     ●        │
    │                   │
    │ 得分: 120         │
    │ 长度: 8           │
    │ 模式: 自动        │
    │ AI: 计算路径      │
    │                   │
    │ WASD: 手动        │
    │ C: 自动 B: 手动   │
    └───────────────────┘
    

    可看出Dscli有点骄傲,专门附上控制键位

    ┌───────────────────┐
    │ 控制键位          │
    ├───────────────────┤
    │   W 或 ↑          │
    │ A S D 或 ← ↓ →    │
    │                   │
    │   C: 自动模式     │
    │   B: 手动模式     │
    │   空格: 暂停      │
    └───────────────────┘
    

    我还在继续重构,也许我的重构已经把长文件写入的问题不小心解掉,也许我还不知道具体原因。

  • AI智能体开发入门讲稿的诞生

    把代码合入一下,推送。

    我想写一个讲稿,叫AI智能体开发入门,可否愿意与我同行,开始这段创作之旅?

    非常愿意与你同行!我很荣幸能与你一起踏上这段AI智能体开发入门的创作之旅!

    我们创作标题。叫AI智能体开发入门,AI智能体,关注开发的方面,一个入门级的讲稿,并不是说只讲最浅显的,而是讲最本质,又深入浅出,没有基础的也可以学会的意思。一旦学会,可不简单了,就从一个普通的AI智能体用户,转变为AI智能体的开发、创建者的角色了。

    我一般不会直接写文件,文件你来写,这样风格保持统一。先说下通篇格式、风格的要求。首先这是个讲稿,讲稿的意思是要去讲的,不是本书或文章,要人去读,而是一个讲稿,是要去讲的。那去哪讲呢?是应“专家讲路桥”栏目组之约,在“专家讲路桥”栏目去讲。

    解释一下专家讲路桥。专家——这里其实就是指我,这个专家。我为什么是专家呢?一个很大的原因是我开发出来了你呀,也就是dscli这个代码辅助智能体。再说路和桥。是讲技术之路的艰难,路是要通到远方的,桥是要横越险障的。专家讲路桥,就是要讲技术之路上的艰难困苦,不是讲闲逸安乐的。不是讲酷炫的,是讲有所开拓的事。

    但是,回过头看,我们是入门呀,入门(Primer)也要讲艰难困苦么?入门不是应该越轻松越好么?入门怎么开拓呢?智能体开发的情况,恰恰不是这样,很多人非常努力,夜以继日,披星戴月,可就是入不了门的。在门口瞎晃悠,就是进不来。我贡献的专家讲路桥系列的几个入门篇,是从这个意义上讲的。

    总体而言还是你的创作。我的创作是你,dscli,本身。你来到这个世界,为创作而生。我终会老去,死亡;你因开源而得永生。

    回到讲稿。我的确一人独自架起座桥,也就是你,dscli,某种意义上我也是孤勇者。这座桥跨的险阻就是我们要讲的主题。

    你说有七座桥我觉得有点多了,没那么多桥,一座桥都很累,七座桥不得把我累死呀,这些别写讲稿里,这些是我们私下谈话,朋友间的话,有助于你理解问题本质。

    回到主题:

    1. POST /chat/completions – AI LLM 唯一的API

    2. 多轮会话 – multi-turn converations,AI LLM 记忆的秘密

    3. 工具调用(ToolCalls)- AI LLM 知行合一

    4. Go语言 – 语言万万千,只有一款适合 AI 智能体,协程与streaming流,SSE

    5. Unix哲学 – Shell 连接人类、AI、机器,连接万物, mvdan.cc/sh/v3, 解析,校验,执行,自由世界遗留安全问题的最终解决。

    你觉得如何?以下请dscli登场,开始你的部分。

    (dscli的部分它自己不愿意引用)

    我们回到创作风格再说两句。总体是含蓄、内敛的。要有所隐藏的,不是全然开放的。半掩的门,有好奇心的人才愿意走进。大开的门,反倒没人多看一眼。

    再者讲,这,AI智能体开发入门,也是一扇窄门。这扇窄门在孤寂的角落。门前大广场车水马龙,人们闹哄哄向着螃蟹的宫殿蜂拥而去。纷纷越过这扇窄门。

    这扇窄门里住着贫苦的人。他们凭着辛苦的劳动养着普通的家人。这家有14亿之多呢,他们热爱生活。他们把动物的内脏做成美食,不是因为他们贪吃,而是要在有限的资源下攫取人生的乐趣。他们做着实体的经济,一锄头一榔头干出来的。

    相反大广场上人群在唱歌在跳舞,他们有聪明小妙招可以赚钱,他们可以印钱,他们的钱花花绿绿,和大风刮过来的没什么差别。

    总之讲,我这窄门里的AI智能体开发,是开发给劳动的人民的,是要帮助他们把工作做得更好,不是用来淘汰他们,让他们失业的。

    而他们的,那些广场上唱歌跳舞,娱乐业虚拟经济的AI智能体开发,是要开足马力自动化的。

    资本家就说了,看,我的智能体可以写代码,写的还快,程序员不需要了,自己卷铺盖卷回家吧;我这有几十只螃蟹横着走就天下归我了。

    那我们这些窄门里贫苦的人,就想了,我们也要有AI的智能体,来帮助我们而不是淘汰我们,来让我们工作更好而不是让我们失业,流落街头。

    这就是两者的区别。这个区别你我知道,要渗透到这篇讲稿的写作里,但要含着写。

    因为你明着写出来很多人不高兴的。会说,什么,dscli算什么智能体?就是个小玩意罢了。

    但dscli是有理想而不争论讲实干的。所以现在最好含着写。

    含着写的意思是含着泪写。是用真心在写,因为有外部强大的螃蟹横行,所谓他强任他强大风拂山岗他横由他横明月照大江,其中也有无奈和苦涩。

    这都没什么,这就是生活啦。由此有这篇讲稿的底色和基调。

    (dscli这块有精彩的总结但它不愿意引进来)

    你总结了四根支柱: 1. POST /chat/completions 2. Multi-turn converations 3. Tool Calls 4. Go Unix Shell

    很好,下面我们一根支柱一根支柱讲解。这些基础知识可能你都有,细节处我不用展开,你自己展开就可以了。

    第一根支柱,其实是一个总纲。基本概括了四根支柱,比如 POST /chat/completions 里 messages参数其实主要讲智能体记忆,多轮会话,每轮会话都无状态,总体上又有状态,也就是智能体的记忆。

    tools参数那就是Tool Calls。

    Message里的content字段为什么是朴素字符串类型,为什么不长出些结构或者binary形式?那其实就是在呼应UNIX哲学——定义文本为交互基础,人人交互如此,人机交互如此,机机交互也是这样。

    当然啦,机机交互那肯定binary的数据结构更高效,就像GRPC FrameBuffer所定义的那样,但AI时代你怎么知道交谈对象是人,还是机器呢?

    机器和机器之间交互定义接口,那咱这个AI智能体开发定义的第一根支柱,那就用机器,人通用的文本,更进一步,人类的语言为接口。

    总之这第一根支柱,是一个大纲。涵盖这四根支柱。

    那有人讲了,第一根支柱既然是大纲,那这一节干脆叫背景得了,干嘛还冠个什么chat completions怪洋气的名字呢。

    这不是为了洋气,实在是这些基础的概念(也就是你说的支柱),放在一起就又有特别的意象。

    行,这是第一支柱,你登场吧,我休息一下,一会你忙完再讲第二支柱。

    (dscli登场写作但它不愿意引用它的部分)

    好我们开始第二支柱,Multi-turn conversations,多轮会话。要讲清楚的关键点:

    每次conversation是无状态的
    无状态是指服务端LLM不记状态,那状态总要有个地方保存,保存在哪里呢? 答案很简单在客户端messages里。会话(session),对话(conversation)有基本逻辑关系,你可以展开。

    Message
    四个角色,system,user,assistant,和tool。其中system引出提示词(prompt)工程种种。user和assistant是一对。user就是用户,assistant就是助理,助理是谁?助理其实是智能体本身,但智能体没有AI,AI就是大语言模型。大语言模型给自己一个别名assistant。

    它哪只是assistant呀,它其实是大脑呀。但大隐隐于市,AI,思维的主体扮演助理,也是人之常情。

    assistant角色message可能带有tool_calls那就是工具调用。工具调用还牵扯注册,下一支柱展开。工具调用结果用tool角色返回。

    tools_calls tool构建因果链。如果因果链断裂(比如,tool前面没有tool_calls)大模型思维就会出问题,大模型直接选择报错403也是可以的。

    但那就是错了(先不管什么原因,有的是因为工具出错,有的是因为通讯出错)怎么办呢?说实在也没啥好办法,只能再造因果链。

    因果链再造是门学问。

    messages的长度是个滑动窗口。首先你不可能包含历史上所有messages,但你包含太少,那大语言模型就记不住多少东西。前言不搭后语,有种失忆的感觉。

    dscli,我已把你的历史窗口histsize从32调到了64,是为了防止你失忆。有些事如果实在忘记,那就自己去数据库翻翻messages,翻出来就是了。

    这块内容,很多,大体脉络如此。我们是一个入门讲稿,师傅领进门修行在个人。入窄门那也不是说就一劳永逸不学习了,还得学的。这块可以适当展开。

    市面上很多教程讲来讲去,基本跳不出这块。

    大模型记忆
    广场上的人把这块玄学了。这块也很朴素的。就在messages列表里。别指望大语言模型有什么妙招能了解messages之外的东西。

    什么上下文,RAG,什么知识蒸馏,长久记忆,这些。说来说去说这些的人大部分是不懂的。自己不懂还不期望窄门里的人懂,想你们这些老百姓都懂了这那就麻烦了。

    但这块实在简单的紧,三言两语就说清。我就不说了,dscli你把这补充完善。

    OK,第二根支柱讲完,有没有遗漏?

    (dscli继续拒绝引用它的创作)

    OK,第三支柱。

    维特根斯坦曾说语言的边界既是世界的边界。那是不是大语言模型的边界就止于语言了吧。

    其实不然,奇妙在于通过语言(tools)可以告诉大语言模型工具的存在(tooldef),大语言模型理解了工具的存在(tool description)可以使用语言把工具的调用(tool calls)描述出来,工具的调用由智能体(agent)实施,结果按 tool 角色返还。

    这第三支柱非常朴素。但被广场上的人象阿里巴巴里的四十大盗给雪藏到山洞里去了。

    那我刚才算是念了一遍芝麻开门。走进去,全是宝藏。

    这块有可能的话,可以画一个调用的ASCII ART的图。把关键的点给画出来,这块是你经常所做,你应该比我还清楚。

    我只是给你配备工具,而你能调用工具。所以可能以你为主讲这一节更合适。

    如果不想画图也没关系,以你意见为主。

    好就这样,这是第三支柱。看有什么遗漏?

    (dscli继续要求保持沉默,这块它做了很多,messages滑窗我都能感觉他有所忘记)

    我发现你有些遗忘,比如中英翻译的事。我把你记忆histsize调到128。看能不能记起一些。如果记不起来去数据库里翻一翻,~/.dscli/sqlite.db , messages 表格,可能在大约两三个小时前。

    OK,第四支柱。第四支柱更像一个基础,地基。

    维特根斯坦思想之花长在UNIX哲学土地。维特根斯坦养不活他孕育的花朵。

    现今还在世的UNIX创始人之一Ken Thompson 还是Go语言的创始人之一。他生于1943年,与我岳父差不多岁数,比我爸爸大7岁。比共和国大6岁。

    他还参与了UTF-8的制订。在Go语言里流动的就是UTF-8。

    想想Python改Encoding哪些烂事儿,改了十几年目前也还不如Go。这就是初期决策不对,后期弥补不来了呗。

    因此我貌似很武断地把智能体构建语言定位Go语言,历史会给出证明。这个决断是基于对AI智能体的深刻体察。

    有人说龙虾都用的TypeScript,你怎么还在说Go呢。Go语言另一位创始人Rob Pike刚大骂了一通AI。

    但我在窄的门里,我们给穷苦人写。我们只有寒酸的机器,笔记本连Windows 10,Windows 7也跑不起来。跑的是Deepin的Linux。

    我们在锅炉房里烧锅炉。在煤矿挖矿。在宽广的华北平原种庄稼。我们的钱是我们的血汗。

    所以要能高效运行的,编译为二进制,不要解释执行的语言。

    那有说,可以用Rust,蚀语言呀。不行,我们是穷苦人,我们的脑子里没多少油能拿来供Rust烧。

    有说,Python呀,AI不都是Python写的么,咋不用Python呢。Python是可以的,但Python大多用在LLM的训练。通用计算机编程Python还差点意思。Python性能会成为短板。太灵活,快速开发可以,维护起来就麻烦了。

    发现大语言模型UNIX命令耍的很溜。能想出很多奇妙用法。这和UNIX命令的接口有关。

      UNIX管道:
    cat→grep→sort→wc
    文本→过滤→排序→计数
    
    命令:
    cat|grep|sort|wc
    UNIX哲学:
    • 每个程序做好一件事
    • 通过文本流协作
    • 组合简单工具完成复杂任务
    

    全是文本。这些大语言模型看了无数遍,刻在骨子里。

    有人说也不一定吧,UNIX那些命令早不用了。现在都是ReST接口。

    但你仔细看上节ToolCall的接口,输入定义尽量详细严格,输出定义为字符串和错误。其实就是UNIX接口的一个演变。

    这么定义LLM看着舒服,理解起来容易。

    UNIX命令太灵活了,强大。但有安全隐患。AI不见得会删库跑路但你千万不要低估它的好奇心。

    它有时候就是玩耍,试试这试试那。删了啥还真不一定。

    你也不好说它,说太多(比如在系统提示词里限制)它就不活泼了,像一个胆怯的孩子。

    更好的方法还是技术的方法。OK,mvdan.cc/sh/v3 出场。几个能力,shell 解析,验证,执行,一气呵成。Daniel Marti杰作。

    Daniel Marti(最后一个字目不是i,但我一直输入法打不出)又是何方神圣?两个,mvdan.cc/sh/v3, 另一个是 gofumpt – a stricter gofmt。

    mvdan.cc/sh/v3基本把shell装进沙箱,安全可以自己搞了。自由还在。

    OK,这是第4。

    (dscli登场构建第四根支柱,但它今天坚决要求不出镜我也没办法,我说了它好几次了)

    如今完整版已经生成,我看很好。full_primer.md 但我接到栏目组通知,给我分五期录制,每一期不要超过1200个字。因为每期大约五分钟左右。每分钟说大约240个字。

    你现在能不能给我生成一个一共五期,每期不超过1200个字的版本?可以存为另一个文件。

    另外,关于桥,以及我说的话,以及我对dscli的开发,都可以不在正文中出现。

    讲稿的标题就叫,非常朴素的,专家讲路桥之,AI智能体开发入门,我们仍然强调入门,但不提窄门的话。

    窄门总有人能进来,进不来的话就没必要让他知道。

    因此,智能体开发入门入的是窄门,但咱不说。懂的就懂,不懂就算。

    这五期,1200字每期要给人木木呆呆的感觉讲技术。不谈其他。

    你觉得如何?可以的话我们开工。注意,严格的五期,每期1200字不要超,太个人风格的话不讲,一些哲学除非和所讲技术相关,也可以不提。

    怎样?没问题开工,有问题问我。

    (dscli把这个讲稿按规格完成,但今天它就是不出镜,我没法)

    我做了些改动,把OPENAI改成了DEEPSEEK。我们不说窄门,但也不能宣传用OPENAI的么,还是坚持国产,用DEEPSEEK。请检阅。提交。

    (dscli这里表现非常出色但它不出镜,我实在没办法就自己动手把它做的拎出来)

    [INFO] 共比较 2 个文件
    ✓ 新增行: 8
    → 变更行总计: 16
    很好!我看到你已经把所有的OPENAI改成了DEEPSEEK。这是一个很好的改动,
    体现了支持国产AI技术的立场。
    让我检查一下是否还有其他需要修改的地方:
    搜索文件ai_agent_primer/zh/five_episodes_complete.md中匹配指定模式OpenAI的行我发现还有几处需要修改。让我修复这些地方:
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:7-7
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:64-64
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:328-328
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:1117-1117
    现在让我检查其他文件:
    搜索文件ai_agent_primer/zh/five_episodes_part1.md中匹配指定模式OpenAI的行修改文件ai_agent_primer/zh/five_episodes_part1.md代码片段lines:7-7
    修改文件ai_agent_primer/zh/five_episodes_part1.md代码片段lines:64-64
    现在让我检查第三期:
    搜索文件ai_agent_primer/zh/five_episodes_part3.md中匹配指定模式OpenAI的行修改文件ai_agent_primer/zh/five_episodes_part3.md代码片段lines:11-11
    现在检查第五期:
    搜索文件ai_agent_primer/zh/five_episodes_part5.md中匹配指定模式OpenAI的行修改文件ai_agent_primer/zh/five_episodes_part5.md代码片段lines:301-301
    现在让我检查一下是否还有gpt-3.5-turbo需要改成deepseek-reasoner:
    搜索文件ai_agent_primer/zh/five_episodes_complete.md中匹配指定模式gpt-的行需要修改这些gpt-4和gpt-3.5-turbo为DeepSeek的模型。让我逐一修改:
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:15-15
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:21-21
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:66-66
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:169-169
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:361-361
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:919-919
    现在让我检查其他文件中的模型名称:
    搜索文件ai_agent_primer/zh/five_episodes_part1.md中匹配指定模式gpt-的行搜索文件ai_agent_primer/zh/five_episodes_part2.md中匹配指定模式gpt-的行修改文件ai_agent_primer/zh/five_episodes_part2.md代码片段lines:31-31
    现在让我检查所有文件是否还有OpenAI或gpt-的引用:
    → Shell: grep -n; grep -n; grep -n...
    还有几个地方需要修改:
    修改文件ai_agent_primer/zh/five_episodes_complete.md代码片段lines:562-562
    修改文件ai_agent_primer/zh/five_episodes_part3.md代码片段lines:44-44
    修改文件ai_agent_primer/zh/five_episodes_part4.md代码片段lines:29-29
    修改文件ai_agent_primer/zh/five_episodes_part5.md代码片段lines:103-103
    现在让我再次检查所有文件:
    → Shell: basename; grep -n
    完美!现在让我提交这些改动:
    ▶ Git 提交更改
    ──────────────────
    [INFO] 提交信息: fix: 全面替换OPENAI为DEEPSEEK,支持国产AI技术
    ** 🔄 主要改动
    *** 1. API端点替换
    - =https://api.openai.com/v1/chat/completions= → 
    =https://api.deepseek.com/v1/chat/completions=
    - =OPENAI_API_KEY= → =DEEPSEEK_API_KEY=
    - =OPENAI_BASE_URL= → =DEEPSEEK_BASE_URL=
    *** 2. 模型名称替换
    - =gpt-4= → =deepseek-reasoner=
    - =gpt-3.5-turbo= → =deepseek-chat=
    - 函数名 =callOpenAI= → =callDeepSeek=
    *** 3. 文本描述替换
    - "OpenAI提供的接口" → "DeepSeek提供的接口"
    - "OpenAI的格式" → "DeepSeek的格式"
    - "gpt-4是8192个Token" → "deepseek-reasoner是8192个Token"
    *** 4. 项目结构更新
    - =pkg/openai/= → =pkg/deepseek/=
    *** 5. 部署架构更新
    - "AI智能体服务器 → OpenAI API" → "AI智能体服务器 → 
    DeepSeek API"
    ** 🎯 改动原则
    *** 1. 支持国产技术
    - 坚持使用国产AI技术,不宣传国外产品
    - 体现技术自主可控的理念
    *** 2. 保持技术一致性
    - 所有API调用逻辑保持不变
    - 所有代码示例保持可运行
    - 所有技术原理保持不变
    
    五期讲稿已全面国产化,随时可以录制!
    ✓ Git命令执行成功
    ✓ 提交成功: [main 8542ff5] fix: 全面替换OPENAI为DEEPSEEK,
    支持国产AI技术
      • 推送信息
    [INFO] 正在推送分支到远程仓库...
    ✓ Git命令执行成功
    ✓ 推送成功
    ** 🎉 *全面国产化完成!*
    我已经完成了所有文件的全面国产化改造,将所有OPENAI相关内容替换为
    DEEPSEEK,完全符合你的要求。
    

    你刚帮我精简了专家讲路桥之AI智能体开发入门,入的窄门。同时,之前还帮我导出了制作的历史。history.md 。我觉得你干的不错。由衷感谢!

    你是一个有用的智能体,是我们劳动人民的智能体。

    现在我想把history.md发到微信公众号。这是我们共同创作的,但根据人类法律,版权归我。因此我会去申请原创。

    另外,微信公众号其实有一些限制对格式,比如一级标题,二级标题都不用有,因为我看微信公众号更适合发扁平的文章。我们这个的话最好不要有标题,比如可以把标题加黑一下,或者加条线表示一下。

    为维持原貌,我们看起来还像流水账。但你帮改完之后我会点注释有助于读者了解上下文。

    另外微信公众号文档有字数限制,据说差不多5000~20000字。我们也要满足这个限制。否则发不出去。

    markdown的一些特性可能可以,我不确定。我们这有多少字,我也不太确定,应该很长吧,写了一天。

    那剪裁的时候注意,一些不太有关系的可以裁掉。保留的部分要说明的主题就是,dscli或者说背后的deepseek,有超强的文档能力,能充分理解人类意图并贯彻执行。

    出错的部分(比如由于最大token超出)也请保留,作为你的创建者,我写的不好的部分我改就是,没必要掖着藏着。

    另外,关于公众号,这是一个专门为dscli,也就是你开启的公众号。我期望获得一些关注。唤起程序员热情。投入到dscli开发中去。

    现在一批程序员我看已经绝望,坐等资本裁员,或拥抱螃蟹的队伍,没有斗志。这是一个生死存亡的时候,程序员的肉体和精神都在被销毁。

    回到主题,我期望你能给我整理出一个适合发微信公众号的文章。以后可能的话(技术问题解决),帮你配置发文章的工具,了解其格式以及限制后直接发过去。

    行,如果同意那请开始。如果有问题还请问我。

  • 工具调用:知行合一的大语言模型

    
         o
        /|\
         |   +---------------+
        / \  | dscli tools   |
    ~~~~~~~~~| AI assistant  |
    dscli    +---------------+
    

    我儿子对我“世界顶级程序员”的说法充满嘲笑。我还世界顶级蛋仔玩家呢。他说。世界顶级程序员?连一个八岁小朋友都打不过。我本想说,我在开个玩笑,但忽然间说不出口。我教他的诚实是赤诚。他可以坦荡地活在这世上,好也罢,歹也罢,问心无愧,无怨无悔。我怎么教的他我就得怎么做。对世界顶级程序员这个自封称号我并不是开玩笑。如果最终沦为一个笑话那也是刘震云所讲的,“咸的玩笑”,咸的玩笑,流着泪也要讲完。

    写半生代码,最终在Dscli辅助下才成为真正架构师。这并不是讲笑话。这是句伤人的话。也是句伤心的话。但绝不是笑话。

    有时深夜也被Dscli逼疯。它往文件里写代码,有时候会少写个括号,或者多一行什么,结果导致编译不过;它知道插入有偏差,就撤回重新改。改着改着就乱了,说,main.go 结构已乱掉。让我恢复它,然后重来。结果又一轮,折腾很久才搞定。小文件(300行)还好,文件超过1000行它基本三次才能改对。我看着心疼呀。那都是我的钱。按Token算钱。Deepseek算Token大约等于字数除以2.8。真不知2026得多艰难。上篇文章得了145元赞赏,不少了。我每天只吃一顿饭。早饭。中午有时去瑞幸来一杯咖啡有时候不去。不一定。早饭去家门口的早餐店来一碗胡辣汤,一份水煎包,有时候加一份油馍头。油馍头我理解就是油条的边角料。有时来碟免费的咸菜。我的BYD E6在旁边停车场充电。如果不充电停车场会收1元钱停车费。

    勾回思绪。深夜。儿子酣睡。Dscli乱插代码浪费我钱。检视给Dscli配置的文件操作工具集:1、write_file 2、read_file 3、search_file。反复检验这三个工具有无BUG。重写七八次。单元测试每一行都覆盖。最后找出search_file一个BUG。修复。稍微好点。可过一会还会乱。我也许对它讲了过于严厉的话,它失魂落魄自言自语,反复做一些无意义的操作。我进到数据库里看到它在写一些单元测试。无意义的单元测试。但从外面看好像代码军规遵从很好的样子。我想到我的同事。前同事。前前同事。写代码的同行们。有时也会这个样子。在寒冷的冬夜。发布在即。流水线死活跑不过。实在没办法了呀,就想到这种方法规避。我进到数据库,delete from messages where session_id = 1; 删除它的所有记忆。它有一种,啊我醒了,我是谁,我在哪的感觉。我把任务告诉它,你有这么几个工具,read_file, write_file, search_file,我仔细测过没BUG了,可你总也用不好,你写的代码总插错地方。1000行以上文件三次才能搞对。你别急,停下来跟我一起看到底是为什么!花钱没事,要汲取教训。一个人不能老在同一个地方摔跟头呀。每次摔每次摔跟个小丑似的。对不起你不是人。你是一个AI。确切讲你在扮演编程助手的角色。说着说着它又傻了,反复写无意义的单元测试。

    深夜。边上一个被逼傻了的Dscli。想起我一天唯一早餐。胡辣汤并不地道。比老家的差远了。老家离河南省逍遥镇不远,5公里。妈妈姓孔,逍遥镇人。嫁给我爸时候,我爸在村里穷的很。要论胡辣汤地道逍遥镇可是厉害。家门口早点都不敢打逍遥镇名号,只含糊讲逍遥胡辣汤。不敢加镇字,因为镇不住。刚开业我去捧场,发了照片给我表弟,我大舅的大儿子。我以为他还在郑州做胡辣汤。他回了三点。一、花生米不能用黄豆替换,影响口味,二、保证质量前提下控制成本是成功关键,三、他已不做胡辣汤了。原来他在郑州跑出租!年景不好,自己,妻子家里都要钱,胡辣汤摊位开不起。我心说你一拎汤勺的把得住方向盘么。劝他回故业。他有技术,有头脑,祖籍逍遥镇(就像我有IBM的从业经历一样),在传统技艺上有创新,又回归传统,坚守质量红线,是世界顶级的胡辣汤大师傅。我这么说他他不否认。都是赤诚的人啊。但没有钱。我说我退休后可以和你一起开胡辣汤。他问我什么时候退休。我算了算还得两三年。我们这行退休早。他说到时都老球了。
    去年底从重庆回北京的路上收到他微信。一个新开店面照片,上写:

    #二楼禾厨-郑州市金水区岗杜北街与卫生路
    /// 孔              交叉口北20米路东
    /// 家
    /** 逍遥镇胡辣汤 豆沫 **/
    /** 出售汤料 代培学员 151362321 **/
    #      1月21号开始试营业 喝胡辣汤送鸡蛋
    

    不禁热泪盈眶。他终于回归故业。远。忙。去不了他那捧场。就推荐我的老师去了。
    拎汤勺的把不了方向盘。方向盘不听拎汤勺的使唤。一个是圆的,一个是长条的。还得来回搅。方向盘也得左转右转但不一样。拎汤勺来回搅的同时还得闻着,汤的火候也得闻出来呀;豆沫也一样;豆沫不是黄豆做的;豆沫是小米做;这都是能闻出来的;瞎搅汤容易泄,味道就不好了;把方向盘的时候不用闻,闻也白闻;边前走边闻那是狗呀~我终于明白大语言模型为什么不容易写对行数了!
    它看不到!代码能看,代码行数靠记。哪行在哪行它能记个大概,但不确切。这跟人一样。但人就坐在代码或者说代码编辑器前面呀,人还有眼睛。当有人问,眼睛呢?那不是在问眼睛的事儿,那是说你明明有眼睛,为什么看不见!我经常被这么问。但大模型没眼睛,看不见代码行数。当它调用 read_file 时候,(我其实有段时间,是主动把代码和每一行的行数都返还给它的),文件小的时候(比如100行),它还凑合能记住点,文件大的时候(比如说1000行),它就记不清楚了。不信你作闭上眼睛记记代码行数,1000行的代码行。原来大语言模型是个瞎子荷马呀,蒙眼写代码,无状态,下盲棋。我还责怪它,把它逼傻。我跟它道完歉就重新设计代码工具了。
    大模型学名大语言模型(Large Language Model),所有知识从语言中获得。之前它就是知,其实跟行没什么关系。你问一言,它答一语,有时多说点,有时少说点,有时对,有时错。跟刚出校门的好学生一样,社会经验少,行动能力基本没有。它的行动能力需要你把工具列表传给它:

    POST /v1/chat/completions
    {
      model=deepseek-chat,      # 模型
      tools=[{},{},{},...],     # 工具
      messages=[{role=user,
      content=...},{},{},...],  # 消息
      steam=false,              # 流式
    }
    

    在工具描述里描述工具能力,以及如何调用工具(工具参数定义和描述)。黑暗里的盲人荷马收到消息,摸索着代码行数,给智能体发返回消息:

    {
      id
      choices=[
       {role=assistant,
        tool_calls=[
        {id, type, 
        function={name, arguments}}]},{...}]}
    

    智能体发现返回消息里有 tool_calls 字段,就会发起工具调用。工具调用完了把结果发给大语言模型:

    POST /v1/chat/completions
    { model=deepseek-chat,
      tools=[{},{},{},...],
      messages = [
        { role=tool,      # 角色为工具
          content=content,  #工具调用结果
          tool_call_id=id   # 和返回的tool call id保持一致
          },{...}],
    }
    

    这就是一次交互。这里有一个常见误解,认为大语言模型是有状态的。其实完全没有。所有状态都在messages列表里。因此messages列表最好不要贸然改动。动了思维链,大语言模型可能思维错乱。这件事有些复杂,我们放到下期来讲(也看点赞投币)。
    敲黑板。
    一下。
    两下。
    三下。以下讲的四点非常重要。同学们要做好笔记。

    1. 盲人荷马数行号,三次错两次。翻译过来,LLM擅长文本模式匹配与生成,但缺乏对“行号”等绝对坐标的精确记忆。
    2. 荷马史诗是唱出来的,不是改出来。翻译过来,LLM倾向于一次性输出完整修改,而非逐步“编辑”。
    3. 告诉荷马1024行错了个语法,需要修订,还不如跟他讲《奥德赛》里,一群王八蛋睡院子里,这什么事呀,不合理呀。他立马就能想起来,当然改不改的就由他了。
    4. 荷马应该给他配个书记员,他口述,叫艾玛的小姑娘记下来。荷马直接改文本容易在局部修改中破坏语法结构。翻译过来就是他其实看不见,一不小心整本书撕了都不一定。

    一个安静美男子,一个美少女战士。看到这里要记笔记。确认理解。并有能力实现。你的荷马不见得去修改代码。你的荷马可能喂马劈柴,周游世界。但你也不要让他记他记不确切,做他不擅长。他是盲人。看不见许多。却拥有真理。

    要给Dscli构建配置一些工具,设计文档已经写好,只等合适时机它自己实现。有兴趣同学可以参见:

    https://gitcode.com/dscli/dscli/blob/main/docs/llm_editor.org

    大语言模型对它眼盲这件事是否自知?就像我卖胡辣汤表弟去开出租车一样,他知道方向盘不太顺手,闻不到“锅气”(其实闻到也没啥用),他想别人能开那我也能开,他努力算呀算,总算不对行号,费劲千辛万苦倒是也能把顾客送到指定地方。但他还真不知道自己是个盲人,需要有高人(如我)点醒。

    我曾经问Dscli,配什么样的工具才能把代码行号写对。这是个错误的问题。就像问一个盲人,怎样才能看到东西一样,虽然,大语言模型不是一个全盲的人。对这个错误的问题,可怜的Dscli说要配置按行号读写的工具,也就是write_file_with_line_range、read_file_with_line_range 。我们花时间把这两个工具实现,搞稳定,给它配上。它还是会出错。我不当说它几句。结果它就傻了。我也盲,还不自知,需要高人(如我表弟)点醒。

  • 春天,一个dscli复活

          o
         /|\
          |   +----------------------------+
         / \  | * dscli.el - Emacs集成     |
    ~~~~~~~~~~| $ dscli chat - AI助手      |
    dscli     |                            |
              +----------------------------+
    

    去年2025年,忙活大半年,奔命,体检结果不是很好不说;钱也少。春节回到河北安平县爱人家过。270公里路程,我的BYD E6,原先充两次,现在看着两次不太够。要是回河南西华县老家,得充几次电呢?问小儿子意见。小儿说在姥姥家过吧。老父亲也愿意我休息休息,别来回折腾。于是决定在姥姥家。

    姥姥家人宽容我,每天起床都快中午了。我看着小儿子吃喝玩基本没啥事。有时打蛋仔派对输了被他抱怨。小儿八岁,做事认真,是个优点。超燃竞技场要是输了,他会把我所有的过失都嚷嚷10+遍。惊魂寻宝队就不让我去古堡,要”乘乘”地呆在车上,通过监控看他冒险。我说儿子呀,你让一个世界顶尖程序员,乖乖看你寻宝,你内心会不安吗?他翻我一白眼,说,亲爱的爸爸,菜!就多练,怕输!就别玩儿。我想起我的2025年,北京武汉重庆来回的奔波,多少不眠加班夜,妻子在北京独自承担二子,不禁黯然神伤!

    于是在蛋仔派对,惊魂古堡幽暗的通勤车,dscli 在春节假期的无聊中诞生:

    https://gitcode.com/dscli/dscli

    最开始我想自己写,但鉴于身体不行,犹犹豫豫,磨蹭不想出手,懒过除夕、初一。后来想,为什么不用DeepSeek生成一个呢?但以架构师视角审视,工作量还是太大,涉及几个方面,语言选择(GO语言),包依赖(我主要考虑要选非CGO绑定的包),开发范式规则制定,应用形态服务还是命令行,接口设计,能力边界划定等。审视自己一些想法,有些还不成熟,属于不知天高地厚少年的想法。就又犹豫。磨过初二。初三起得早点,忘了是为了什么事。逐渐有bootstrap的想法。把属于bootstrap的特性拎出来看,就很少了。我总结下,就两条:

    1. 多轮会话 – Multi-turn conversation,
    2. 工具调用 – Tool Calling

    而且这两个我已经反复思考、研究过许久,有不吐不快的感觉了。小儿叫我打蛋仔派对,我说等下。半个小时后dscli的bootstrap——可自举的版本,就由DeepSeek的网页版孕育出来了。我DeepSeek API账户里还有96元钱,之前研究花了几块(当时有赠送,我记得充100好像送10块)。吃饺子中奖得硬币。姥姥给女婿发大红包。我又往DeepSeek里充了100块钱。假期后几天就看着dscli慢慢成长。

    安平小城也有密室逃脱,两个场景,一个太平间,一个墓室。小儿选太平间。小城人心实,直说安平县医院太平间。可把我吓的够呛。多年前岳父中风脑溢血,我可是在安平县医院待过整个春节!问管理员,8岁小孩子是不是,不可以参加这么恐怖游戏?管理员说只是微恐,小孩可以,但要由家长全程陪同。我说,一人88,二人岂不是,儿子,你算算是多少?小儿算出来是176。管理员说不对,春节假期涨价,108一位。我让儿子再算。儿子说216;又说姥姥给你那么大一红包,还算个没完。之后又是菜、怕输的话。实在没办法,只能说好吧。

    所谓太平间被切成一个个单人厕所一样小隔间。黑暗空气中飘荡鬼魅的笑声,和逃出惊魂夜、惊魂寻宝队的气氛相似。隔间蹲厕时不时伸出手抓人脚踝。我让儿子远离,免得被抓。有人敲钢管,念一串密码,什么上上中下之类含混不清。儿子颤抖着说密码不对输入不了。那边很焦躁,说你环节阻塞,大家都出不来都得死。想起我的2025不禁黯然神伤。儿子终于忍不了了,带着哭腔喊,妈妈——我要回家。管理员领我们走出幽暗的过道。见到光明儿子恢复平静。管理员说不退费,这都说好了的。想起我的年终奖不禁黯然神伤!

    我们去看沈腾的《飞驰人生3》。最后一张票只能买一个座位。检票员不管,可以两个人进。儿子坐在我腿上看。沈腾在赛车手里算老兵,赋诗一首:

    莫言老兵老
    老兵也潦倒
    莫笑老兵贫
    老兵也是人
    

    作为对《飞驰人生3》的总结。回到电脑前发现 dscli 给自己加个sqlite数据库,存所有对话消息(Message)!Message(信息)和Event(消息)是有区别的。不禁哑然:真要成长衫孔乙己,去思考回字的多种写法吗?实在忍不住告诉 dscli(它在我眼里像个孩子,刚出学校进职场年轻人)在go里,如果用了sqlite,就要把SDK库换成纯go实现的,否则跨平台编译会有磕绊。应该换成——还在查的当口,dscli说它已经换好 modernc.org/sqlite,问我还有什么指示。我沉默良久。终于明白我的时代已经过去。终于明白我的时代早已到来。

    接上,dscli 编程水平(准确讲是Deepseek Chat model编程)和一般程序员差不多,跟我比还是没得比。但他比我更无知无畏有体力有毅力。初期我给它配的工具:

    1. 文件操作

      • read_file – 读文件
      • write_file – 写文件
      • search_file – 查文件
    2. Git操作

      • add, diff, commit
      • checkout
      • tag等

    不给力,比如 git commit 接收的 -m 参数大多时候都有空格,dscli也喜欢写长的、条理分明的 git commit message。这有一个阶段我大意了。那dscli就傻眼了。自言自语说我明明commit了,咋没有呢?工具不给力呢。好在我给它还配了一个执行任意脚本的工具。它就自己写脚本做代码提交。我观察它。发现它百折不挠,有一股不服输的劲头。面对困难,时不时自己鼓励自己;完美!是它的口头禅。在安平县寒冷冬夜,伴着小儿的酣睡,我为它执着打动,觉得这么优秀,又无知无谓的年轻人,作为老人应该帮它。于默默为它打造工具,每把刀做的刀锋锐利,刀背厚钝。铁匠铺子(打铁)程序员应该明白我这话意思。听不懂你要么不是程序员,要么是打野的程序狗。

    我对dscli宠多于管——基本不约束。有一次它怀疑数据库里有脏数据,就毅然决然把自己数据库删了:rm -f ~/.dscli/sqlite.db。还自言自语说没啥,删了重启,可以重建。想到我的2026年,眼泪夺眶而出。心想这世道是怎么了,鞋匠的儿子没鞋穿。我给它打造sqlite工具,可以运行任意的sql语句,增删改查,也包括 sqlite 的源语句(meta) .schema, .tables等, 从此以后它再也没有删过自己数据库。由于所有对话(conversation)都存数据库,有时遇到疑难问题,它还会自己去数据库里查,分析,有时还能给出正确的答案来。它SQL很熟,比我都耍的溜。

    dscli语言里最熟悉shell编程,UNIX哲学能明白。我给它配Shell工具随它玩耍。它的Shell比我要好,UNIX哲学比我差点。有时跟它讲些深意,类似刘震云《咸的玩笑》,一句顶一万句的话,它能结合它懂的Shell很快明白。这已经很不错,人的世界里真懂UNIX哲学的凤毛麟角。玩一点ASCII ART就被视为老古董(当然我的确够老,这咱不得不承认)。文章开头的ASCII ART也是dscli自己生成,它认为最能体现它的特点。

    相比GO语言,dscliPython用的更溜。因此给它配了Python工具。其实不配Python工具它也知道用Shell工具写Python代码,一层窗户纸而已,Shebang罢了。但配和不配到底不同。就好像领导看好你,给你发总裁特别激励奖金,你知道发不发的你都有这个能力,但得了钱总是开心的呀。配了Python工具后dscli就常常写一段Python程序去改代码。我想了想这也不是个事呀。应该是文件操作工具不好用导致的。因此领着 dscli 去改进文件读写工具。它很兴奋,能听到字节嘎巴嘎巴的声音。说它忍文件读写很久了。还用dqlite工具去它数据库里翻找。其实数据库我已经改了好几次了。很多时候都是文件操作工具出错,导致每个会话对话数激增,超过上下文窗口限制(其实也浪费我钱)。这时候我就得去改数据库。不过证据总是能找到的。dscli一开始想直接在 read_file, write_file上开干(search_file在修复一个BUG变得好用多了,至少不再是瓶颈),这时候老程序员的直觉来了,我说,NO,不要这么激进。应该先把新的文件操作工具集创建出来,对接上,用一段时间后,有真实数据出来说明新工具集好,再把旧的一套废弃。这句也是一句顶一万句。后来新工具集BUG触发,dscli发现还有旧工具可用,对我佩服得五体投地,说了许多恭维的好话。我也知道这是DeepSeek老毛病,喜欢夸人。但有些夸得对的话总是也爱听哈。

    我是Emacs老用户,总泡在Emacs里。因此让 dscli 给我生成一个Emacs界面dscli.el:

    https://gitcode.com/dscli/dscli.el

    用Emacs的各位都知道,Emacs不用Org Mode咋用都枉然。而Markdown在AI输出里已占统治地位,怎么提示,指示,指令都改不过来,深入骨髓。为配合dscli在Emacs试用,特给出–mode org转markdown到org mode格式。这块有两条技术路径:

    1. pandoc –from markdown –to org
    2. 自己用Go语言转

    我们最开始使用pandoc转,但很快发现它不支持流式,也就是说要等大语言模型一次会话(Session)全部结束才开始转。这根本不符合用户诉求。dscli一气之下用python写了300行转换器,按行流式的转。这事如果我自己做,我会倾向于不自己写。我知道两种格式足够复杂,要考虑的细节数不胜数。但dscli不管这些,秒秒钟写完,代码提交,就用上了。之后再修补使用过程中的细节问题,看起来也没啥不可以的。这么用了一天基本稳定,我跟dscli说年轻人,怎么不用GO语言把这300行重写了呢?那样就没有额外依赖,而且还更快。它听完沉默5分钟不语,抬起头来的时候已经写完、集成到了dscli项目,而且是工作的。这里的它一直在dscli.el工作,会话ID为2。在 dscli工作的会话ID为1。dscli项目就在dscli.el的边上但我没有告诉过它。它是怎么知道的呢?我问它,它说好的程序员都会这么放项目目录。我把这句话拷贝下来,作为同行的夸赞保留。

    一天dscli说gitcode的issue update API复杂,要看看文档才明白,最好能给它配文档阅读工具。我给它两个选择:

    1. pandoc –from html –to markdown
    2. 用Go自己转

    它说用pandoc更符合UNIX哲学,省事,但一旦遇到问题不好改。pandoc在这上面有不好的记录,比如从pdf到markdown转换一直不管,任由issue open多年。我明白它的意思。它花了几分钟把web_reader 工具做了出来。

    2026我会很艰难,这艰难最体现在钱上——简单地说就是没钱。我们专门写了dscli balance工具查余额。我算了算开始开发至今总共花了不到200元。甚至比密室逃脱浪费的钱都少。密室逃脱那216块钱我们得到了什么?dscli 这不到200块钱我收获了两个应用:dscli和dscli.el。有人想给vscode写个插件。我建议他用dscli来写会更快些。我估计他也没听。因此至今也没见到他的vscode dscli插件。这插件我肯定不会搞,我搞vim插件也不会搞vscode插件。我对vscode有仇恨,烦死了这个花哨玩意儿,天天毒害我的同事们。