语义搜索:用自然语言找代码
Windsurf 的搜索有两种模式:传统的文本搜索(精确匹配)和 AI 语义搜索(理解意图)。切换方式:在搜索框(Cmd/Ctrl+Shift+F)右侧点击"AI"图标开启语义模式。
语义搜索 vs 文本搜索对比:
查询:「处理用户登录失败的逻辑」
文本搜索结果(关键词匹配):
→ 搜索 "用户登录失败" → 0 结果
→ 搜索 "login" → 47 个结果(大量不相关)
→ 搜索 "login fail" → 3 结果(可能遗漏关键文件)
语义搜索结果(理解意图):
→ src/auth/handlers.ts:142 handleAuthError()
→ src/middleware/rateLimit.ts:28 checkFailedAttempts()
→ src/services/audit.ts:67 logAuthFailure()
→ src/constants/errors.ts:12 AUTH_ERROR_CODES
(精准命中 4 个最相关位置,不遗漏不冗余)
语义搜索的实用查询示例:
// 功能定位
"邮件发送逻辑"
"支付回调处理"
"数据库连接初始化"
// 问题排查
"可能导致内存泄漏的地方"
"所有直接使用 eval 的代码"
"没有错误处理的异步函数"
// 架构理解
"全局状态管理的入口"
"API 路由注册的地方"
"中间件是如何串联的"
让 AI 解释代码
遇到复杂的代码块(正则表达式、复杂的 Redux reducer、性能优化代码),选中后打开 Cascade(Chat Mode)或内联聊天(Cmd+I),让 AI 解释:
// 选中代码后,在 Cascade Chat Mode 中问:
解释这段代码的作用,重点说明:
1. 整体的处理逻辑(用中文,不要逐行翻译)
2. 关键变量的含义
3. 为什么要这样设计(相比简单实现有什么优势)
4. 可能的边界情况和潜在 bug
实战示例:解释一段复杂的 Go 并发代码
// 你选中这段代码,问 AI 解释:
func fanOut(ctx context.Context, src <-chan Job, n int) []<-chan Result {
dsts := make([]<-chan Result, n)
for i := range dsts {
dst := make(chan Result)
dsts[i] = dst
go func() {
defer close(dst)
for {
select {
case job, ok := <-src:
if !ok { return }
dst <- process(job)
case <-ctx.Done():
return
}
}
}()
}
return dsts
}
/* Cascade 解释(节选):
这是一个"扇出"并发模式的实现:
整体逻辑:将一个输入 channel(src)的工作负载
分发给 n 个并行的 worker goroutine,每个 worker
独立处理任务并将结果写入自己的输出 channel。
关键设计:
- ctx.Done() 监听:任一 worker 都可以被外部取消
- defer close(dst):worker 退出时自动关闭输出
channel,通知消费方不再有数据
- select 多路复用:避免 goroutine 在两个
channel 上分别阻塞 ... */
查找相关文件:AI 辅助影响分析
修改一个函数之前,需要知道哪些文件会受到影响。Cascade 能帮你做完整的影响分析:
我准备修改 @src/models/User.ts 中的 User interface,
把 `name: string` 拆分为 `firstName: string` 和 `lastName: string`。
请帮我:
1. 找出代码库中所有使用了 User.name 的地方
2. 按修改难度分类(简单替换 / 需要逻辑调整)
3. 列出修改顺序建议(先改哪个文件,再改哪个)
4. 预估总改动量(文件数和大概行数)
暂时不要修改,先给我分析报告。
Cascade 会使用 search_codebase 工具检索所有引用,生成类似这样的分析报告:
// Cascade 响应示例:
影响分析报告:User.name → firstName + lastName
直接引用(11 处):
简单替换(7 处):
- src/components/UserAvatar.tsx:23 user.name → user.firstName
- src/pages/Profile.tsx:45 user.name → `${user.firstName} ${user.lastName}`
- src/api/users.ts:67 response.name → response.firstName
... (省略4处)
需要逻辑调整(4 处):
- src/utils/sort.ts:12 按 name 排序 → 按 lastName 排序
- src/search/index.ts:34 全文搜索 name → 需要同时搜索两个字段
- src/export/csv.ts:89 CSV 列名映射需要更新
- src/db/migrations/ 需要新建 migration 文件
推荐修改顺序:
1. src/models/User.ts(核心类型定义)
2. src/db/migrations/(数据库层)
3. src/api/users.ts(API 序列化/反序列化)
4. 其余 UI 组件(独立,可并行)
大型代码库技巧
超过 10 万行的代码库需要特殊策略,避免上下文溢出和性能下降:
模块化处理
不要让 Cascade 一次性处理整个代码库,按模块拆分任务。先让它理解一个模块(如 auth/),完成该模块的任务后,新建 Cascade 会话处理下一个模块(如 payment/)。每个会话的上下文保持清洁,AI 的输出质量更高。
提供架构文档
在 Cascade 任务开始时,先粘贴一段项目架构描述(或让 AI 读取 README),让它"了解全局"再处理局部。例如:"这是一个 monorepo,packages/api 是 Node.js 后端,packages/web 是 React 前端,packages/shared 包含共享类型。"
指定搜索范围
在 Prompt 中明确告诉 Cascade 只关注哪些目录,避免它在不相关的区域浪费搜索时间。例如:"只修改 src/features/checkout/ 目录,不要碰其他功能模块。"
遗留代码现代化
Windsurf 非常适合处理遗留代码库——理解"老式写法"并将其转换为现代风格,同时保持功能不变。以下是一个完整的迁移 Prompt 示例:
@src/legacy/dataProcessor.js 这个文件写于 2018 年,
使用了 jQuery 风格的回调嵌套和 var 声明。
请将它现代化,要求:
1. ES2022+ 语法(const/let, async/await, 可选链 ?., 空值合并 ??)
2. 保持所有原有功能(不能改变任何业务逻辑)
3. 添加 TypeScript 类型(输出 .ts 文件)
4. 每个函数添加 JSDoc 注释
在修改前,先分析原代码的功能,确认我的理解是否正确。
遗留代码迁移的风险提醒
AI 在将回调风格转换为 async/await 时,可能改变代码的执行顺序(如并行变串行)。务必要求 Cascade"说明所有可能的行为变化",并在迁移后运行完整的测试套件验证功能等价性。如果没有测试,建议先让 Cascade 补充测试,再做迁移。
本章小结
语义搜索让"找代码"从关键词匹配升级为意图理解,特别适合陌生代码库的上手。AI 代码解释能快速理解复杂逻辑,影响分析能在修改前评估风险。大型代码库应采用模块化处理策略,避免单次会话上下文过长。遗留代码现代化是 Windsurf 的强项,但务必验证行为等价性。