Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added MCP终极指南-进阶篇/img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions MCP终极指南-进阶篇/weather/mcpServers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"mcpServers": {
"weather": {
"disabled": true,
"timeout": 60,
"type": "stdio",
"command": "python",
"args": [
"/Users/liujia/code/learn/rag/VideoCode/MCP终极指南-进阶篇/weather/mcp_logger.py",
"uv",
"--directory",
"/Users/liujia/code/learn/rag/VideoCode/MCP终极指南-进阶篇/weather",
"run",
"weather.py"
]
}
}
}
5 changes: 5 additions & 0 deletions MCP终极指南-进阶篇/weather/mcp_io copy.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
输入: {"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"sampling":{},"roots":{"listChanged":true}},"clientInfo":{"name":"mcp","version":"0.1.0"}},"jsonrpc":"2.0","id":0}
输出: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"experimental":{},"prompts":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"weather","version":"1.6.0"}}}
输入: {"method":"notifications/initialized","jsonrpc":"2.0"}
输入: {"method":"tools/call","params":{"name":"get_forecast","arguments":{"latitude":40.7128,"longitude":-74.006}},"jsonrpc":"2.0","id":1}
输出: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"\nOvernight:\nTemperature: 69°F\nWind: 7 mph SW\nForecast: Mostly cloudy. Low around 69, with temperatures rising to around 71 overnight. Southwest wind around 7 mph.\n\n---\n\nThursday:\nTemperature: 85°F\nWind: 6 to 14 mph SW\nForecast: Mostly sunny. High near 85, with temperatures falling to around 81 in the afternoon. Southwest wind 6 to 14 mph.\n\n---\n\nThursday Night:\nTemperature: 68°F\nWind: 8 to 13 mph SW\nForecast: A slight chance of rain showers between 2am and 5am. Mostly cloudy. Low around 68, with temperatures rising to around 70 overnight. Southwest wind 8 to 13 mph. Chance of precipitation is 20%.\n\n---\n\nFriday:\nTemperature: 77°F\nWind: 10 mph NW\nForecast: A chance of rain showers after 8am. Mostly sunny. High near 77, with temperatures falling to around 75 in the afternoon. Northwest wind around 10 mph. Chance of precipitation is 30%.\n\n---\n\nFriday Night:\nTemperature: 60°F\nWind: 9 mph NE\nForecast: A chance of rain showers before 8pm. Partly cloudy. Low around 60, with temperatures rising to around 62 overnight. Northeast wind around 9 mph. Chance of precipitation is 30%.\n"}],"isError":false}}
6 changes: 3 additions & 3 deletions MCP终极指南-进阶篇/weather/mcp_io.log
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
输入: {"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"Cline","version":"3.12.3"}},"jsonrpc":"2.0","id":0}
输入: {"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"Cline","version":"3.78.0"}},"jsonrpc":"2.0","id":0}
输出: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"experimental":{},"prompts":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"weather","version":"1.6.0"}}}
输入: {"method":"notifications/initialized","jsonrpc":"2.0"}
输入: {"method":"tools/list","jsonrpc":"2.0","id":1}
Expand All @@ -7,5 +7,5 @@
输出: {"jsonrpc":"2.0","id":2,"result":{"resources":[]}}
输入: {"method":"resources/templates/list","jsonrpc":"2.0","id":3}
输出: {"jsonrpc":"2.0","id":3,"result":{"resourceTemplates":[]}}
输入: {"method":"tools/call","params":{"name":"get_forecast","arguments":{"latitude":40.7128,"longitude":-74.006}},"jsonrpc":"2.0","id":4}
输出: {"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"\nToday:\nTemperature: 64°F\nWind: 2 to 18 mph S\nForecast: Mostly sunny. High near 64, with temperatures falling to around 62 in the afternoon. South wind 2 to 18 mph, with gusts as high as 30 mph.\n\n---\n\nTonight:\nTemperature: 57°F\nWind: 12 to 17 mph S\nForecast: Mostly cloudy. Low around 57, with temperatures rising to around 59 overnight. South wind 12 to 17 mph, with gusts as high as 29 mph.\n\n---\n\nSaturday:\nTemperature: 78°F\nWind: 12 to 21 mph SW\nForecast: Partly sunny, with a high near 78. Southwest wind 12 to 21 mph, with gusts as high as 32 mph.\n\n---\n\nSaturday Night:\nTemperature: 57°F\nWind: 15 to 18 mph W\nForecast: A chance of rain showers between 8pm and 2am. Mostly cloudy. Low around 57, with temperatures rising to around 61 overnight. West wind 15 to 18 mph. Chance of precipitation is 30%.\n\n---\n\nSunday:\nTemperature: 62°F\nWind: 14 to 17 mph NW\nForecast: Partly sunny, with a high near 62. Northwest wind 14 to 17 mph.\n"}],"isError":false}}
输入: {"method":"prompts/list","jsonrpc":"2.0","id":4}
输出: {"jsonrpc":"2.0","id":4,"result":{"prompts":[]}}
9 changes: 0 additions & 9 deletions MCP终极指南-进阶篇/weather/mcp_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,6 @@ def forward_and_log_stdout(target_stdout, proxy_stdout, log_file):
daemon=True
)

# Optional: Handle stderr similarly (log and pass through)
stderr_thread = threading.Thread(
target=forward_and_log_stdout, # Can reuse the function
args=(process.stderr, sys.stderr.buffer, log_f), # Pass stderr streams
# Add a different prefix in the function if needed, or modify function
# For now, it will log with "STDOUT:" prefix - might want to change function
# Let's modify the function slightly for this
daemon=True
)
# A slightly modified version for stderr logging
def forward_and_log_stderr(target_stderr, proxy_stderr, log_file):
"""Reads from target's stderr, logs it, writes to proxy's stderr."""
Expand Down
254 changes: 254 additions & 0 deletions MCP终极指南-进阶篇/weather/mcp_logger_optimized.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
#!/usr/bin/env python3

import sys
import subprocess
import threading
import argparse
import os

# --- 配置 ---
LOG_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "mcp_io.log")
# --- 配置结束 ---

# --- 参数解析 ---
parser = argparse.ArgumentParser(
description="Wrap a command, passing STDIN/STDOUT verbatim while logging them.",
usage="%(prog)s <command> [args...]"
)
# 接收命令及其后续所有参数
parser.add_argument('command', nargs=argparse.REMAINDER,
help='The command and its arguments to execute.')

open(LOG_FILE, 'w', encoding='utf-8')

if len(sys.argv) == 1:
parser.print_help(sys.stderr)
sys.exit(1)

args = parser.parse_args()

if not args.command:
print("Error: No command provided.", file=sys.stderr)
parser.print_help(sys.stderr)
sys.exit(1)

target_command = args.command


# --- 参数解析结束 ---

# --- I/O 转发函数 ---
# 以下函数会在独立线程中运行

def forward_and_log_stdin(proxy_stdin, target_stdin, log_file):
"""从代理标准输入读取,记录日志后写入目标标准输入。"""
# 参数含义(对应线程 args):
# proxy_stdin = sys.stdin.buffer(当前脚本的输入口,数据从上游流入这里)
# target_stdin = process.stdin(子进程的输入口,数据要被喂给它)
try:
while True:
# 从当前脚本的标准输入逐行读取
line_bytes = proxy_stdin.readline()
if not line_bytes: # 已到达 EOF
break

# 为日志解码(默认按 UTF-8,必要时可调整)
try:
line_str = line_bytes.decode('utf-8')
except UnicodeDecodeError:
line_str = f"[非 UTF-8 数据, {len(line_bytes)} 字节]\n" # 日志中的替代展示

# 记录日志前缀
log_file.write(f"输入: {line_str}")
log_file.flush() # 确保日志及时写盘

# 将原始字节写入目标进程标准输入
# 也就是把当前脚本收到的输入“喂给子进程”
target_stdin.write(line_bytes)
target_stdin.flush() # 确保目标进程及时接收

except Exception as e:
# 记录转发过程中的异常
try:
log_file.write(f"!!! STDIN Forwarding Error: {e}\n")
log_f.flush()
except:
pass # 若日志文件异常,避免二次报错

finally:
# 关键:代理输入结束时要关闭目标 stdin
# 这样会向目标进程发送 EOF 信号(类似 shell 中 read 结束)
try:
target_stdin.close()
log_file.write("--- STDIN stream closed to target ---\n")
log_file.flush()
except Exception as e:
try:
log_file.write(f"!!! Error closing target STDIN: {e}\n")
log_file.flush()
except:
pass


def forward_and_log_stdout(target_stdout, proxy_stdout, log_file):
"""从目标标准输出读取,记录日志后写回代理标准输出。"""
try:
while True:
# 从目标进程标准输出逐行读取
line_bytes = target_stdout.readline()
if not line_bytes: # 到达 EOF(进程退出或关闭 stdout)
break

# 为日志进行解码
try:
line_str = line_bytes.decode('utf-8')
except UnicodeDecodeError:
line_str = f"[非 UTF-8 数据, {len(line_bytes)} 字节]\n"

# 写入带前缀的日志
log_file.write(f"输出: {line_str}")
log_file.flush()

# 将原始字节写到当前脚本标准输出
proxy_stdout.write(line_bytes)
proxy_stdout.flush() # 确保输出及时可见

except Exception as e:
try:
log_file.write(f"!!! STDOUT Forwarding Error: {e}\n")
log_file.flush()
except:
pass
finally:
try:
log_file.flush()
except:
pass
# 这里不要关闭 proxy_stdout(即 sys.stdout)


# --- 主执行流程 ---
process = None
log_f = None
exit_code = 1 # 默认退出码,表示提前失败

try:
# 以追加模式打开日志文件,供各线程写入
log_f = open(LOG_FILE, 'a', encoding='utf-8')

# 启动目标进程
# stdin/stdout/stderr 都通过管道连接
# 采用字节流并关闭缓冲(bufsize=0,readline 仍可用)
process = subprocess.Popen(
target_command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, # 同时捕获标准错误
bufsize=0 # 0 表示无缓冲二进制 I/O
)

# 将二进制流交给线程处理
# sys.stdin.buffer: 当前脚本从外部接收到的“原始字节输入”入口(不是文本流)
# process.stdin: 子进程的标准输入管道(往这里 write 就是在给子进程喂输入)
# args 顺序映射:args[0] -> proxy_stdin,args[1] -> target_stdin,args[2] -> log_file
stdin_thread = threading.Thread(
target=forward_and_log_stdin,
args=(sys.stdin.buffer, process.stdin, log_f),
daemon=True # 主线程退出时允许守护线程一并退出
)

# process.stdout: 子进程的标准输出管道;从这里读到子进程的正常输出
# sys.stdout.buffer: 当前脚本对外输出的“原始字节出口”,可原样透传避免编码干扰
stdout_thread = threading.Thread(
target=forward_and_log_stdout,
args=(process.stdout, sys.stdout.buffer, log_f),
daemon=True
)


# 标准错误的转发与日志函数
def forward_and_log_stderr(target_stderr, proxy_stderr, log_file):
"""从目标标准错误读取,记录日志后写回代理标准错误。"""
try:
while True:
line_bytes = target_stderr.readline()
if not line_bytes: break
try:
line_str = line_bytes.decode('utf-8')
except UnicodeDecodeError:
line_str = f"[非 UTF-8 数据, {len(line_bytes)} 字节]\n"
log_file.write(f"STDERR: {line_str}") # 使用 STDERR 前缀
log_file.flush()
proxy_stderr.write(line_bytes)
proxy_stderr.flush()
except Exception as e:
try:
log_file.write(f"!!! STDERR Forwarding Error: {e}\n")
log_file.flush()
except:
pass
finally:
try:
log_file.flush()
except:
pass


stderr_thread = threading.Thread(
target=forward_and_log_stderr,
args=(process.stderr, sys.stderr.buffer, log_f),
daemon=True
)

# 启动三个转发线程
stdin_thread.start()
stdout_thread.start()
stderr_thread.start() # 启动标准错误线程

# 等待目标进程结束
process.wait()
exit_code = process.returncode

# 短暂等待 I/O 线程收尾并刷新最后日志
# 线程是守护线程,主线程退出时可能被直接结束
# join 可让关闭过程更平滑
# process.wait() 后子进程结束,管道通常会自然关闭
stdin_thread.join(timeout=1.0) # 设置超时,避免线程卡死
stdout_thread.join(timeout=1.0)
stderr_thread.join(timeout=1.0)


except Exception as e:
print(f"MCP Logger Error: {e}", file=sys.stderr)
# 尝试将主流程异常写入日志
if log_f and not log_f.closed:
try:
log_f.write(f"!!! MCP Logger Main Error: {e}\n")
log_f.flush()
except:
pass # 忽略最终日志写入中的异常
exit_code = 1 # 表示 logger 执行失败

finally:
# 若子进程仍在运行,确保将其结束(如 logger 异常中断)
if process and process.poll() is None:
try:
process.terminate()
process.wait(timeout=1.0) # 先给一次优雅退出机会
except:
pass # 忽略清理阶段的异常
if process.poll() is None: # 仍未退出
try:
process.kill() # 强制结束
except:
pass # 忽略强杀异常

# 关闭日志文件
if log_f and not log_f.closed:
try:
log_f.close()
except:
pass # 忽略最终关闭日志时的异常

# 使用目标进程退出码退出
sys.exit(exit_code)
27 changes: 27 additions & 0 deletions 使用Python构建RAG系统/rag/downLoad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import os

# 清除所有代理设置(确保)
proxy_vars = ['HTTP_PROXY', 'HTTPS_PROXY', 'http_proxy', 'https_proxy', 'NO_PROXY', 'no_proxy', 'ALL_PROXY', 'all_proxy']
for var in proxy_vars:
os.environ.pop(var, None)

# 设置 HF-Mirror 镜像
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'

print(f'✓ 代理已清除')
print(f'✓ 镜像已设置: {os.environ.get("HF_ENDPOINT")}')
print('\n开始下载模型...')

from sentence_transformers import SentenceTransformer

embedding_model = SentenceTransformer("shibing624/text2vec-base-chinese")

print('✓ 模型加载成功!')

# 测试
def embed_chunk(chunk: str):
embedding = embedding_model.encode(chunk, normalize_embeddings=True)
return embedding.tolist()

embedding = embed_chunk("测试内容")
print(f'嵌入维度: {len(embedding)}')
31 changes: 27 additions & 4 deletions 使用Python构建RAG系统/rag/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
# 项目元数据配置
[project]
name = "rag"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"

# 项目依赖包列表
dependencies = [
"chromadb>=1.0.15",
"google-genai>=1.24.0",
"python-dotenv>=1.1.1",
"sentence-transformers>=5.0.0",
"chromadb>=1.0.15", # 向量数据库,用于存储和检索文档嵌入
"google-genai>=1.24.0", # Google Generative AI 客户端
"python-dotenv>=1.1.1", # 环境变量管理,用于加载 .env 文件
"sentence-transformers>=5.0.0", # 文本嵌入模型,将文本转换为向量
]

# 启动 Jupyter Lab 的命令:
# uv run --with jupyter jupyter lab
#
# 命令详细执行步骤:
# 1. uv 检查:当前目录是否有 pyproject.toml 或 requirements.txt? → 有(本文件)
# 2. uv 检查:全局缓存是否有已安装 jupyter 的环境? → 没有
# 3. uv 在缓存目录自动创建临时环境,并通过 pip 安装 jupyter
# 4. 在这个临时环境中启动 jupyter lab 命令
#
# 说明:
# --with jupyter 参数表示在当前项目环境中临时安装 jupyter,无需将 jupyter 添加到项目依赖中
# 这样可以保持依赖清单干净,避免将开发工具部署到生产环境

# PyPI 镜像源配置
[[tool.uv.index]]
name = "tuna"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
default = true

Loading