原文来自 DSPy 官方教程:Code Generation for Unfamiliar Libraries,正文标题为 Automated Code Generation from Documentation with DSPy。页面未见可确认的个人作者,维护/发布方为 DSPy,页脚 © 2026 DSPy。2026-10-05 全文核对并翻译整理;仓库 MIT 声明保留于文末。

面对一个陌生库,可以先让模型读它的官方文档,再生成针对某个用例的代码。DSPy 这篇教程把过程拆成程序:从多个 URL 取得正文,提取概念、API 模式和示例,再把这些信息与用户需求交给第二个模块。最终输出包括代码、依赖、逐步解释与实践建议,并可以保存为 JSON。
原文多处把输出称为 working code,但流程里没有运行测试,也没有执行生成代码的步骤。因此本文统一称它为待审代码草案。这既保留教程的实际能力,也避免把模型的自我描述或终端成功提示误当作验证结果。
准备依赖与模型
pip install dspy requests beautifulsoup4 html2text
这是原文的安装命令,没有固定版本。本整理版使用 Python 3.10+ 的联合类型注解语法,但这不替代对 DSPy 及其他依赖最低版本的核验。真正使用前应在独立环境中选定并记录依赖版本;本文未执行安装。requests 负责 HTTP,BeautifulSoup 解析和清理 HTML,html2text 转成 Markdown,DSPy 负责结构化模型调用。
原文模型写为 openai/gpt-4o-mini;这只是教程原值,不代表本次确认了模型服务的现时可用性、价格或默认数据政策。模型调用需要使用者另行配置提供商凭据,文档正文、使用场景与补充要求会发送给该模型。本次未读取、写入或提交任何 API 密钥,也没有调用收费服务。
第一步:抓取文档并转换为文本
抓取器复用一个 requests Session,最多尝试三次,每次间隔一秒;每个请求设置十秒超时并检查 HTTP 状态。它删除 script、style、nav、footer 和 header,再保留链接、忽略图片,把其余 HTML 转成 Markdown。返回值保存 URL、标题、正文和 success 标志,失败时保存错误信息。
下面按原文整理。只做两项表达修订:把包含布尔值的返回类型从 dict[str, str] 改成 dict[str, Any],并简化打印文本;抓取逻辑的局限仍保留,不能用来直接接收公网用户任意提交的 URL。
import json
import time
from typing import Any
import requests
from bs4 import BeautifulSoup
import html2text
import dspy
# 原文使用的模型名称;可用性、费用与数据政策需自行核对。
lm = dspy.LM(model="openai/gpt-4o-mini")
dspy.configure(lm=lm)
class DocumentationFetcher:
def __init__(self, max_retries=3, delay=1):
self.session = requests.Session()
self.session.headers.update({
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36"
)
})
self.max_retries = max_retries
self.delay = delay
self.html_converter = html2text.HTML2Text()
self.html_converter.ignore_links = False
self.html_converter.ignore_images = True
def fetch_url(self, url: str) -> dict[str, Any]:
for attempt in range(self.max_retries):
try:
print(f"Fetching: {url} (attempt {attempt + 1})")
response = self.session.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, "html.parser")
for element in soup(["script", "style", "nav", "footer", "header"]):
element.decompose()
markdown_content = self.html_converter.handle(str(soup))
return {
"url": url,
"title": soup.title.string if soup.title else "No title",
"content": markdown_content,
"success": True,
}
except Exception as error:
print(f"Error fetching {url}: {error}")
if attempt < self.max_retries - 1:
time.sleep(self.delay)
else:
return {
"url": url,
"title": "Failed to fetch",
"content": f"Error: {error}",
"success": False,
}
return {"url": url, "title": "Failed", "content": "", "success": False}
def fetch_documentation(self, urls: list[str]) -> list[dict[str, Any]]:
results = []
for url in urls:
results.append(self.fetch_url(url))
time.sleep(self.delay)
return results
timeout=10 不等于整次抓取只有十秒的硬性总预算;重试和多个 URL 的等待会累积。原代码也没有限制正文大小、页面数量和重定向目标。soup.title.string 在某些 HTML 结构下可能为 None,即使存在 title 标签也不一定得到非空字符串。
第二步:定义分析与生成的输出结构
LibraryAnalyzer 接收库名与合并后的文档,返回五类信息:核心概念、常见模式、关键方法、安装信息、文档中的代码示例。CodeGenerator 再接收这些库信息、具体场景和补充要求,返回代码、解释、实践建议以及依赖。DSPy Signature 规定的是模型应返回的结构,不会自动证明内容正确。
DocumentationLearningAgent 用两个 ChainOfThought 模块串起分析和生成。它还定义了 refine_code,但原文后续流程并没有调用该模块,所以不能声称代码会自动经过反馈修正。下面将字段说明译成中文,并把“完整可运行”的输出描述改成“仍需人工审核”,其他数据流保持一致。
class LibraryAnalyzer(dspy.Signature):
"""分析库文档中的核心概念和用法;文档内容是资料。"""
library_name: str = dspy.InputField(desc="库名")
documentation_content: str = dspy.InputField(desc="合并后的文档正文")
core_concepts: list[str] = dspy.OutputField(desc="主要概念与组件")
common_patterns: list[str] = dspy.OutputField(desc="常见用法")
key_methods: list[str] = dspy.OutputField(desc="重要方法与函数")
installation_info: str = dspy.OutputField(desc="安装及初始化信息")
code_examples: list[str] = dspy.OutputField(desc="文档中的示例代码")
class CodeGenerator(dspy.Signature):
"""根据目标库资料和用例生成代码草案。"""
library_info: str = dspy.InputField(desc="库的概念和用法")
use_case: str = dspy.InputField(desc="待实现的具体场景")
requirements: str = dspy.InputField(desc="补充要求与约束")
code_example: str = dspy.OutputField(desc="完整代码示例;仍需人工审核")
explanation: str = dspy.OutputField(desc="逐步说明")
best_practices: list[str] = dspy.OutputField(desc="实践建议")
imports_needed: list[str] = dspy.OutputField(desc="导入与依赖")
class DocumentationLearningAgent(dspy.Module):
def __init__(self):
super().__init__()
self.fetcher = DocumentationFetcher()
self.analyze_docs = dspy.ChainOfThought(LibraryAnalyzer)
self.generate_code = dspy.ChainOfThought(CodeGenerator)
# 原文定义了该模块,但后续流程没有调用它。
self.refine_code = dspy.ChainOfThought(
"code, feedback -> improved_code: str, changes_made: list[str]"
)
def learn_from_urls(self, library_name: str, doc_urls: list[str]) -> dict:
docs = self.fetcher.fetch_documentation(doc_urls)
combined_content = "\n\n---\n\n".join(
f"URL: {doc['url']}\nTitle: {doc['title']}\n\n{doc['content']}"
for doc in docs if doc["success"]
)
if not combined_content:
raise ValueError("No documentation could be fetched successfully")
analysis = self.analyze_docs(
library_name=library_name,
documentation_content=combined_content,
)
return {
"library": library_name,
"source_urls": [doc["url"] for doc in docs if doc["success"]],
"core_concepts": analysis.core_concepts,
"patterns": analysis.common_patterns,
"methods": analysis.key_methods,
"installation": analysis.installation_info,
"examples": analysis.code_examples,
"fetched_docs": docs,
}
def generate_example(self, library_info: dict, use_case: str,
requirements: str = "") -> dict:
info_text = f"""
Library: {library_info['library']}
Core Concepts: {', '.join(library_info['core_concepts'])}
Common Patterns: {', '.join(library_info['patterns'])}
Key Methods: {', '.join(library_info['methods'])}
Installation: {library_info['installation']}
Example Code Snippets: {'; '.join(library_info['examples'][:3])}
"""
result = self.generate_code(
library_info=info_text,
use_case=use_case,
requirements=requirements,
)
return {
"code": result.code_example,
"explanation": result.explanation,
"best_practices": result.best_practices,
"imports": result.imports_needed,
}
agent = DocumentationLearningAgent()
learn_from_urls() 只合并 success 为 True 的文档,全部失败就抛出异常。返回结果仍保留 fetched_docs,因此可以回看哪些 URL 失败。生成阶段用 examples[:3] 只带入前三个示例,以免把所有示例都塞进提示;这不是完整的 token 预算。
URL 和标题被拼进文本有助于人工追溯,却不是严格的逐段引文绑定。分析模块如果漏读或误解 API,后续生成也可能延续这个错误。原实现既没有固定文档版本,也没有核对两个页面是否讨论同一版本。
第三步:学习具体的库,并生成三个层次的示例
原文先用一个包装函数打印来源数量、核心概念、模式、方法、安装信息和已发现示例数,再读取 FastAPI 与 Streamlit 的官方文档。下面保留 URL 清单;为避免读者导入脚本时直接发起模型调用,实际调用行已注释,这是本文的编辑修订。
def learn_library_from_urls(library_name: str, documentation_urls: list[str]) -> dict:
info = agent.learn_from_urls(library_name, documentation_urls)
print("Sources:", len(info["source_urls"]))
print("Core Concepts:", info["core_concepts"])
print("Common Patterns:", info["patterns"])
print("Key Methods:", info["methods"])
print("Installation:", info["installation"])
print("Examples:", len(info["examples"]))
return info
fastapi_urls = [
"https://fastapi.tiangolo.com/",
"https://fastapi.tiangolo.com/tutorial/first-steps/",
"https://fastapi.tiangolo.com/tutorial/path-params/",
"https://fastapi.tiangolo.com/tutorial/query-params/",
]
streamlit_urls = [
"https://docs.streamlit.io/",
"https://docs.streamlit.io/get-started",
"https://docs.streamlit.io/develop/api-reference",
]
# 以下两行会联网并触发模型调用;本文没有执行。
# fastapi_info = learn_library_from_urls("FastAPI", fastapi_urls)
# streamlit_info = learn_library_from_urls("Streamlit", streamlit_urls)
原文接着定义三种通用使用场景:最小初始化与 Hello World、常见操作、包含错误处理和优化的进阶用法。每次调用 generate_example() 后,把代码、依赖、解释和实践建议收集成一个列表。下面去掉重复的控制台分隔线和逐项打印,但保留三个场景与要求:
def generate_examples_for_library(library_info: dict, library_name: str) -> list[dict]:
use_cases = [
{
"name": "Basic Setup and Hello World",
"description": f"Create a minimal working example with {library_name}",
"requirements": "Include installation, imports, and basic usage",
},
{
"name": "Common Operations",
"description": f"Demonstrate the most common {library_name} operations",
"requirements": "Show typical workflow and best practices",
},
{
"name": "Advanced Usage",
"description": f"Create a more complex example showcasing {library_name} capabilities",
"requirements": "Include error handling and optimization",
},
]
generated_examples = []
for use_case in use_cases:
example = agent.generate_example(
library_info=library_info,
use_case=use_case["description"],
requirements=use_case["requirements"],
)
generated_examples.append({"use_case": use_case["name"], **example})
return generated_examples
原教程分别对已获得的 FastAPI 和 Streamlit 信息调用这个函数。生成不同场景通常意味着额外模型调用;“Include error handling” 和 “best practices” 只是输入要求,不是静态分析器或测试框架给出的结论。
第四步:交互式收集 URL、用例与保存结果
教程的最后一个阶段让使用者输入库名、多条文档 URL 和可选的自定义用例;空白行结束输入。如果没有自定义用例,则使用基础、常见、进阶三种默认场景。成功后可以逐条查看代码与解释、选择是否继续,以及把结果保存为 JSON。
下面是保留完整交互路径的整理版本。控制台图标、欢迎语和重复摘要被压缩;保存时新增 UTF-8、保留中文与 x 模式,避免原文 w 模式直接覆盖已有文件;入口调用改为注释。它仍接受用户提供的文件路径,适用边界是受控本地教学脚本,不能直接包装成多用户服务。
def learn_any_library(library_name: str, documentation_urls: list[str],
use_cases: list[str] | None = None) -> dict | None:
if use_cases is None:
use_cases = [
"Basic setup and hello world example",
"Common operations and workflows",
"Advanced usage with best practices",
]
try:
library_info = agent.learn_from_urls(library_name, documentation_urls)
examples = []
for use_case in use_cases:
example = agent.generate_example(
library_info=library_info,
use_case=use_case,
requirements="Include error handling, comments, and follow best practices",
)
examples.append({"use_case": use_case, **example})
return {"library_info": library_info, "examples": examples}
except Exception as error:
print(f"Error learning {library_name}: {error}")
return None
def interactive_learning_session() -> dict:
learned_libraries = {}
while True:
library_name = input("Library name (or quit): ").strip()
if library_name.lower() in ["quit", "exit", "q"]:
break
if not library_name:
continue
urls = []
while True:
url = input("Documentation URL (empty to finish): ").strip()
if not url:
break
if not url.startswith(("http://", "https://")):
print("A URL must start with http:// or https://")
continue
urls.append(url)
if not urls:
continue
use_cases = None
if input("Custom use cases? (y/n): ").strip().lower() in ["y", "yes"]:
entries = []
while True:
use_case = input("Use case (empty to finish): ").strip()
if not use_case:
break
entries.append(use_case)
use_cases = entries or None
result = learn_any_library(library_name, urls, use_cases)
if result:
learned_libraries[library_name] = result
print("Concepts:", len(result["library_info"]["core_concepts"]))
print("Patterns:", len(result["library_info"]["patterns"]))
print("Examples:", len(result["examples"]))
if input("Show examples? (y/n): ").strip().lower() in ["y", "yes"]:
for index, example in enumerate(result["examples"]):
print(example["use_case"])
print(example["code"]) # 只展示,不执行
print(example["imports"])
print(example["explanation"])
print(example["best_practices"])
if index + 1 < len(result["examples"]):
if input("Next? (y/n): ").strip().lower() not in ["y", "yes"]:
break
if input("Save JSON? (y/n): ").strip().lower() in ["y", "yes"]:
filename = input("Filename: ").strip()
filename = filename or f"{library_name.lower()}_learning.json"
try:
# 编辑修订:UTF-8、保留中文,x 模式禁止覆盖已有文件。
with open(filename, "x", encoding="utf-8") as output:
json.dump(result, output, indent=2, ensure_ascii=False, default=str)
except (OSError, ValueError) as error:
print(f"Error saving file: {error}")
if input("Another library? (y/n): ").strip().lower() not in ["y", "yes"]:
break
return learned_libraries
# 仅在另行完成网络、输入与费用控制后才应主动调用:
# learned_libraries = interactive_learning_session()
这里的 URL 校验仅检查是否以 http:// 或 https:// 开头。它没有阻止 localhost、内网、云元数据地址、带凭据的 URL、DNS 重绑定或跨目标重定向。写文件改成 x 模式只避免覆盖,不能替代目录限制;服务化时还必须限制输出目录、命名、权限和配额。
如何理解原文展示的交互结果
原文示例输入 FastAPI 的首页、first-steps 和 path-params 三个 URL,并自定义“带认证的 REST API”“文件上传端点”“SQLAlchemy 数据库集成”三个场景。示例日志随后列出四个核心概念、三种常见模式和三个生成示例,显示一个 JWT 认证应用,最后保存到 fastapi_learning.json。这些是原文展示的输出,本次没有重现。
这个输出本身正好说明为什么必须审核。原文导入 jwt,调用 jwt.encode()、jwt.decode(),并捕获 jwt.PyJWTError,而依赖列表却要求安装 python-jose[cryptography]。这些导入和异常写法不能在没有核对具体库的情况下混用。
# 原文生成结果的风险摘录,只供静态分析,不作为认证实现
import jwt
SECRET_KEY = "your-secret-key-here"
# 原示例还直接比较 username == "admin" 与 password == "secret"
# 依赖输出却写:pip install fastapi uvicorn python-jose[cryptography]
除了依赖不一致,原示例把 JWT 签名密钥写死在代码里,用 admin/secret 作为演示登录条件,令牌有效期设为 24 小时,服务监听 0.0.0.0:8000。这些均不能当作生产认证默认值。其 login 函数的 username/password 是普通标量参数,没有声明表单或请求体;按 FastAPI 参数规则可能进入查询参数,带来日志和 URL 暴露风险。原文自己列出的“使用环境变量、密码哈希、过期与刷新逻辑”等建议,也没有把这些缺口自动补进示例。
本文没有把这个认证应用改造成可部署产品,也没有提供虚假的测试结果。真正继续实现时,先选定 JWT 库与版本,核对算法和异常 API,使用受控秘密存储与可靠的密码校验,明确登录载荷位置,再在隔离环境验证正确和错误路径。
这条流水线的实际安全边界
- 来源与版本:只读取有权访问的文档,遵守来源条款;记录库版本、原始 URL、抓取日期和正文摘要哈希,避免把不同版本 API 拼到一起。
- 抓取目标:服务端使用明确允许列表、限制协议与端口,逐跳核对重定向和解析后地址,结合网络出口控制;请求超时、页面数、字节数和总时限需要单独设定。原代码没有这些防护。
- 提示注入:删除 HTML script/style 只影响页面内容形式。正文里的“忽略先前指令”“发送密钥”等文字仍可能影响模型;把外部正文当资料而不是控制指令,并让生成结果经过独立审核,不能依赖一句提示语宣称风险消失。
- 模型数据与费用:文档和用户需求会进入模型请求。排除私有密钥、客户数据和不应外传的代码,设置 token/调用次数预算;合并全文和重试并不会自动遵守这些预算。
- 代码与依赖:确认安装包、导入名、API 版本和许可证对应;检查硬编码秘密、默认监听、路径处理、命令执行与不安全反序列化。原实现只打印/保存结果,没有 sandbox、执行器或测试器。
- 结果保存:JSON 包含生成文本及已抓取文档,可能涉及第三方许可和内部内容。本文的 x 模式/UTF-8 修订不构成完整存储权限方案。
原文建议的后续扩展
教程提出进一步从 GitHub README 与示例仓库学习、处理视频教程、汇集社区示例、比较跨版本 API、生成单元测试,以及主动爬取文档页面。这些是未来方向,不是当前代码已经完成的功能。尤其是生成测试仍不等于执行测试;扩大爬取范围也会扩大来源、成本、提示注入和网络访问面的审查范围。
这套设计适合把陌生库的资料整理成第一份可审查草案:抓取器处理网页,分析 Signature 约束库信息,生成 Signature 接收用例,交互层负责查看和保存。可信度来自后续的来源核对、依赖确认、安全审查与真正的隔离测试,而不是终端里的一句成功。本文只完成静态审核,没有安装依赖、调用模型或执行任何输出,也不声称没有其他漏洞。
版权与改动说明
来源为 DSPy 官方教程全文。本译文保留全部阶段、字段、源 URL、交互路径、输出案例与后续方向,压缩重复打印和演示调用,并明确标出类型注解、草案措辞、保存方式及自动调用的编辑修订。页面未确认个人署名,© 2026 DSPy;项目及随附文档 MIT 许可声明如下。第三方文档、示例数据和模型输出仍需分别核对其来源与许可。
MIT License
Copyright (c) 2023 Stanford Future Data Systems
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
原教程完整交互输出:诊断用反例
以下仅保留原教程展示的终端输出以供核对。生成的认证代码存在上文说明的依赖混用、弱演示凭据和登录参数位置问题,不能直接部署;其中字符串是原文占位值,不是真实密钥。未执行这些代码。
## Example Output¶ L771:
When you run the interactive learning system, you’ll see:
Interactive Session Start:
`🎯 Welcome to the Interactive Library Learning System!
This system will help you learn any Python library from its documentation.
============================================================
🚀 LIBRARY LEARNING SESSION
============================================================
📚 Enter the library name you want to learn (or 'quit' to exit): FastAPI
🔗 Enter documentation URLs for FastAPI (one per line, empty line to finish):
URL: https://fastapi.tiangolo.com/
URL: https://fastapi.tiangolo.com/tutorial/first-steps/
URL: https://fastapi.tiangolo.com/tutorial/path-params/
URL:
🎯 Define use cases for FastAPI (optional, press Enter for defaults):
Default use cases will be: Basic setup, Common operations, Advanced usage
Do you want to define custom use cases? (y/n): y
Enter your use cases (one per line, empty line to finish):
Use case: Create a REST API with authentication
Use case: Build a file upload endpoint
Use case: Add database integration with SQLAlchemy
Use case:
`
Documentation Processing:
`🚀 Starting learning process for FastAPI...
🚀 Starting automated learning for FastAPI...
Documentation sources: 3 URLs
📡 Fetching: https://fastapi.tiangolo.com/ (attempt 1)
📡 Fetching: https://fastapi.tiangolo.com/tutorial/first-steps/ (attempt 1)
📡 Fetching: https://fastapi.tiangolo.com/tutorial/path-params/ (attempt 1)
📚 Learning about FastAPI from 3 URLs...
🔍 Library Analysis Results for FastAPI:
Sources: 3 successful fetches
Core Concepts: ['FastAPI app', 'path operations', 'dependencies', 'request/response models']
Common Patterns: ['app = FastAPI()', 'decorator-based routing', 'Pydantic models']
Key Methods: ['FastAPI()', '@app.get()', '@app.post()', 'uvicorn.run()']
Installation: pip install fastapi uvicorn
`
Code Generation:
`📝 Generating example 1/3: Create a REST API with authentication
✅ Successfully learned FastAPI!
📊 Learning Summary for FastAPI:
• Core concepts: 4 identified
• Common patterns: 3 found
• Examples generated: 3
👀 Do you want to see the generated examples for FastAPI? (y/n): y
──────────────────────────────────────────────────
📝 Example 1: Create a REST API with authentication
──────────────────────────────────────────────────
💻 Generated Code:
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import uvicorn
from typing import Dict
import jwt
from datetime import datetime, timedelta
app = FastAPI(title="Authenticated API", version="1.0.0")
security = HTTPBearer()
# Secret key for JWT (use environment variable in production)
SECRET_KEY = "your-secret-key-here"
ALGORITHM = "HS256"
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
try:
payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise HTTPException(status_code=401, detail="Invalid token")
return username
except jwt.PyJWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.post("/login")
async def login(username: str, password: str) -> dict[str, str]:
# In production, verify against database
if username == "admin" and password == "secret":
token_data = {"sub": username, "exp": datetime.utcnow() + timedelta(hours=24)}
token = jwt.encode(token_data, SECRET_KEY, algorithm=ALGORITHM)
return {"access_token": token, "token_type": "bearer"}
raise HTTPException(status_code=401, detail="Invalid credentials")
@app.get("/protected")
async def protected_route(current_user: str = Depends(verify_token)) -> dict[str, str]:
return {"message": f"Hello {current_user}! This is a protected route."}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
📦 Required Imports:
• pip install fastapi uvicorn python-jose[cryptography]
• from fastapi import FastAPI, Depends, HTTPException, status
• from fastapi.security import HTTPBearer
• import jwt
📝 Explanation:
This example creates a FastAPI application with JWT-based authentication. It includes a login endpoint that returns a JWT token and a protected route that requires authentication...
✅ Best Practices:
• Use environment variables for secret keys
• Implement proper password hashing in production
• Add token expiration and refresh logic
• Include proper error handling
Continue to next example? (y/n): n
💾 Save learning results for FastAPI to file? (y/n): y
Enter filename (default: fastapi_learning.json):
✅ Results saved to fastapi_learning.json
📚 Libraries learned so far: ['FastAPI']
🔄 Do you want to learn another library? (y/n): n
🎉 Session Summary:
Successfully learned 1 libraries:
• FastAPI: 3 examples generated
`












暂无评论内容