Major Changes: - Add StreamingService with OpenAI Compatible format - Upgrade Chat component V2 with Ant Design X integration - Implement AIA module with 12 intelligent agents - Update API routes to unified /api/v1 prefix - Update system documentation Backend (~1300 lines): - common/streaming: OpenAI Compatible adapter - modules/aia: 12 agents, conversation service, streaming integration - Update route versions (RVW, PKB to v1) Frontend (~3500 lines): - modules/aia: AgentHub + ChatWorkspace (100% prototype restoration) - shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook - Update API endpoints to v1 Documentation: - AIA module status guide - Universal capabilities catalog - System overview updates - All module documentation sync Tested: Stream response verified, authentication working Status: AIA V2.0 core completed (85%)
67 KiB
宸ュ叿C - 绉戠爺鏁版嵁缂栬緫鍣?MVP寮€鍙戣<E98D99>鍒?
*鏂囨。鐗堟湰锛? V1.0 (鍔″疄蹇<E79684>€熼獙璇佺増)
*鍒涘缓鏃ユ湡锛? 2025-12-06
*璁″垝鍛ㄦ湡锛? 3鍛<33>紙15涓<35>伐浣滄棩锛? *鏍稿績绛栫暐锛? 鐢ㄦ渶灏忔垚鏈<E59E9A>獙璇佹牳蹇冨亣璁撅紝蹇<E7B49D>€熷け璐ヤ紭浜庡畬缇庤<E7BC87>鍒? 鐘舵€侊細 寰呭惎鍔?
鈿狅笍 寮€鍙戝墠蹇呰<E8B987>锛氫弗鏍奸伒瀹堢幇鏈夋灦鏋勪笌瑙勮寖
馃敶 涓嶈<E6B693>閲嶅<E996B2>閫犺疆瀛愶紒澶嶇敤骞冲彴鑳藉姏
鏈<EFBFBD>」鐩<EFBFBD>凡鏈夊畬鏁寸殑3灞傛灦鏋勪綋绯诲拰骞冲彴鍩虹<EFBFBD>璁炬柦锛屾墍鏈変唬鐮佸繀椤诲<EFBFBD>鐢ㄧ幇鏈夎兘鍔涳細
骞冲彴鍩虹<EFBFBD>灞傦紙鉁?宸插畬鎴愶紝鐩存帴浣跨敤锛?
| 鏈嶅姟 | 瀵煎叆鏂瑰紡 | 鐢ㄩ€? | 鏂囨。 |
|---|---|---|---|
| 瀛樺偍鏈嶅姟 | import { storage } from '@/common/storage' |
鏂囦欢涓婁紶涓嬭浇 | 鉁?蹇呴』浣跨敤 |
| 鏃ュ織绯荤粺 | import { logger } from '@/common/logging' |
鏍囧噯鍖栨棩蹇? | 鉁?蹇呴』浣跨敤 |
| 缂撳瓨鏈嶅姟 | import { cache } from '@/common/cache' |
鍒嗗竷寮忕紦瀛? | 鉁?蹇呴』浣跨敤 |
| 寮傛<EFBFBD>浠诲姟 | import { jobQueue } from '@/common/jobs' |
闀挎椂闂翠换鍔? | 鉁?蹇呴』浣跨敤 |
| *鏁版嵁搴? | import { prisma } from '@/config/database' |
鏁版嵁搴撴搷浣? | 鉁?蹇呴』浣跨敤 |
| LLM鑳藉姏 | import { LLMFactory } from '@/common/llm' |
LLM璋冪敤 | 鉁?蹇呴』浣跨敤 |
浜戝師鐢熷紑鍙戣<EFBFBD>鑼冿紙鉁?寮哄埗鎵ц<E98EB5>锛?
**璇︾粏鏂囨。**锛歚docs/04-寮€鍙戣<E98D99>鑼?08-浜戝師鐢熷紑鍙戣<E98D99>鑼?md`
*鏍稿績瑕佹眰锛?
- 鉁?鏂囦欢瀛樺偍锛氫娇鐢╜storage.upload()
锛屼笉瑕佺敤fs.writeFile()` - 鉁?Session绠$悊锛氬瓨鏁版嵁搴擄紝涓嶈<EFBFBD>鐢╜Map<sessionId, data>`
- 鉁?鏃ュ織杈撳嚭锛氫娇鐢╜logger.info()
锛屼笉瑕佺敤console.log()` - 鉁?**鏁版嵁搴撹繛鎺?*锛氫娇鐢ㄥ叏灞€
prisma瀹炰緥锛屼笉瑕乣new PrismaClient()` - 鉁?LLM璋冪敤锛氫娇鐢╜LLMFactory.getLLM()`锛屼笉瑕佽嚜宸遍泦鎴?
- 鉂?绂佹<EFBFBD>鏈<EFBFBD>湴鏂囦欢瀛樺偍锛欵xcel鐩存帴浠庡唴瀛樿В鏋?
- 鉂?绂佹<EFBFBD>鍐呭瓨缂撳瓨Map锛氱敤鏁版嵁搴撴垨cache鏈嶅姟
- 鉂?**绂佹<E7BB82>纭<EFBFBD>紪鐮侀厤缃?*锛氫娇鐢ㄧ幆澧冨彉閲?
浠g爜鏂囦欢澶圭粨鏋勶紙鉁?鍙傝€僼ool-b锛?
**鍚庣<E98D9A>**锛?
backend/src/modules/dc/tool-c/ 鈫?宸插瓨鍦?
鈹溾攢鈹€ services/ 鈫?涓氬姟閫昏緫
鈹溾攢鈹€ controllers/ 鈫?HTTP鎺у埗鍣?
鈹溾攢鈹€ routes/ 鈫?璺<>敱瀹氫箟
鈹斺攢鈹€ utils/ 鈫?宸ュ叿鍑芥暟
**鍓嶇<E98D93>**锛?
frontend-v2/src/modules/dc/pages/tool-c/ 鈫?宸插瓨鍦?
甯歌<EFBFBD>閿欒<EFBFBD>绀轰緥锛堚潓 涓ョ<E6B693>锛?
// 鉂?閿欒<E996BF>1锛氳嚜宸卞疄鐜癝ession绠$悊
const sessions = new Map<string, any>(); // 杩濆弽瑙勮寖锛?
// 鉂?閿欒<E996BF>2锛氭湰鍦版枃浠跺瓨鍌?
fs.writeFileSync('./uploads/file.xlsx', buffer); // 杩濆弽瑙勮寖锛?
// 鉂?閿欒<E996BF>3锛氫笉鐢╨ogger
console.log('User uploaded file'); // 杩濆弽瑙勮寖锛?
// 鉂?閿欒<E996BF>4锛氭柊寤篜risma瀹炰緥
const prisma = new PrismaClient(); // 杩濆弽瑙勮寖锛?
// 鉂?閿欒<E996BF>5锛氳嚜宸遍泦鎴怢LM
import Anthropic from '@anthropic-ai/sdk'; // 杩濆弽瑙勮寖锛?
**姝g‘绀轰緥锛堚渽 蹇呴』锛?*锛氬弬鑰冩湰鏂囨。Day 1-5鐨勪唬鐮佺ず渚?
馃搵 鐩<>綍
- [寮€鍙戝墠蹇呰<E8B987>](#寮€鍙戝墠蹇呰<E8B987>涓ユ牸閬靛畧鐜版湁鏋舵瀯涓庤<E6B693>鑼?
- 涓€銆丮VP鏍稿績鐩<EFBFBD>爣
- 浜屻€佹妧鏈<EFBFBD>灦鏋勬柟妗堬紙鍔″疄鐗堬級
- 涓夈€佸姛鑳戒紭鍏堢骇鐭╅樀
- [鍥涖€?鍛ㄨ<E98D9B>缁嗗紑鍙戣<E98D99>鍒抅(#鍥?鍛ㄨ<E98D9B>缁嗗紑鍙戣<E98D99>鍒?
- [浜斻€侀<E282AC>闄╁簲瀵圭瓥鐣<E793A5>(#浜旈<E6B59C>闄╁簲瀵圭瓥鐣?
- [鍏<>€侀獙鏀舵爣鍑哴(#鍏<>獙鏀舵爣鍑?
- [涓冦€佸揩閫熷け璐ユ満鍒禲(#涓冨揩閫熷け璐ユ満鍒?
涓€銆丮VP鏍稿績鐩<EFBFBD>爣
1.1 鏍稿績鍋囪<E98D8B>楠岃瘉
鎴戜滑闇€瑕侀獙璇佺殑3涓<EFBFBD>牳蹇冨亣璁撅細
| 鍋囪<EFBFBD> | 楠岃瘉鏂瑰紡 | 鎴愬姛鏍囧噯 | 澶辫触鍚庢灉 |
|---|---|---|---|
| *H1: AI鑳界敓鎴愰珮璐ㄩ噺Pandas浠g爜骞舵垚鍔熸墽琛? | 15涓<EFBFBD>湡瀹炲満鏅<EFBFBD>祴璇? | 鎬讳綋鎴愬姛鐜?> 80% | MVP澶辫触锛屾敼鐢ㄤ唬鐮佹ā鏉垮簱 |
| H2: Python浠g爜鎵ц<E98EB5>鐜<EFBFBD><E9909C>绋冲畾鍙<E795BE>潬 | 澶嶆潅鍦烘櫙娴嬭瘯 | 楂樼骇鍦烘櫙鎴愬姛鐜?> 60% | 绠€鍖栦负鎵瑰<EFBFBD>鐞嗘ā寮? |
| *H3: 宸﹁〃鏍?鍙矨I鐨勪氦浜掓ā寮忓ソ鐢? | 鐢ㄦ埛浣撻獙娴嬭瘯 | 鐢ㄦ埛鑳界嫭绔嬪畬鎴愪换鍔? | 閲嶆柊璁捐<EFBFBD>UI浜や簰 |
| *H4: 鎬ц兘鍙<E58598>帴鍙楋紙鍚玃ython鎵ц<E98EB5>锛? | 鎬ц兘娴嬭瘯 | 绔<EFBFBD>埌绔?< 20绉? | 浼樺寲Python鎵ц<EFBFBD>鎴栨敼鎵瑰<EFBFBD>鐞? |
鈿狅笍 鏍稿績浠峰€间富寮狅細
- 鉁?AI鐢熸垚浠g爜 + 鐪熷疄鎵ц<E98EB5> + 琛ㄦ牸鍒锋柊鏄<EFBFBD>伐鍏稢鐨勫樊寮傚寲浠峰€?
- 鉁?濡傛灉鍙<E78189>敓鎴愪唬鐮佷笉鎵ц<E98EB5>锛岀敤鎴疯繕涓嶅<E6B693>鐩存帴鐢–hatGPT
- 鉁?Python鎵ц<E98EB5>鐜<EFBFBD><E9909C>鏄疢VP鐨?*鎶€鏈<E282AC>牳蹇?*锛屼笉鏄<E7AC89>彲閫夐」
1.2 MVP鍔熻兘鑼冨洿
鉁?MVP蹇呴』鏈夌殑锛圥0锛夛細
- 鏂囦欢涓婁紶锛?0MB闄愬埗锛?
- 琛ㄦ牸灞曠ず锛圓G Grid锛?00琛岄<E7909B>瑙堬級
- AI瀵硅瘽鐣岄潰锛堝彸渚т晶杈规爮锛?
- AI浠g爜鐢熸垚锛圖eepSeek-V3锛?
- 浠g爜鎵ц<EFBFBD>锛圥ython娌欑<EFBFBD>锛?
- UI閿佸畾鏈哄埗锛圓I澶勭悊鏃惰〃鏍煎彧璇伙級
- AST瀹夊叏妫€鏌?
- 琛ㄦ牸鑷<EFBFBD>姩鍒锋柊
- 瀵煎嚭Excel
鉂?MVP鏄庣‘涓嶅仛鐨勶細
- 鎵嬪姩缂栬緫鍗曞厓鏍硷紙涓撴敞AI鑳藉姏锛?
- 鎾ら攢/鍥炴粴锛堣妭鐪佸唴瀛橈級
- Apache Arrow锛堝厛鐢↗SON锛?
- Redis浼氳瘽锛堢敤杩涚▼鍐呭瓨锛?
- 鏍峰紡淇濈暀锛堢洿鎺ヨ<EFBFBD>鐩栵級
- 鎿嶄綔瀹¤<EFBFBD>鏃ュ織
- 鍗忓悓缂栬緫
1.3 MVP浜や粯鐗?
鏈€缁堟紨绀哄満鏅<EFBFBD>細
鐢ㄦ埛涓婁紶 "lung_cancer_patients.xlsx" (5000琛?脳 20鍒?
鈫?
宸︿晶鏄剧ず鏁版嵁琛ㄦ牸锛屽彸渚<E5BDB8>I鍔╂墜鍑嗗<E98D91>灏辩华
鈫?
鐢ㄦ埛瀵笰I璇达細"鎶婂勾榫勫ぇ浜?0鐨勬偅鑰呮爣璁颁负鑰佸勾缁?
鈫?
AI鐢熸垚浠g爜 鈫?灞曠ず棰勬搷浣滃崱鐗?鈫?鐢ㄦ埛纭<E59F9B><E7BAAD> 鈫?鎵ц<E98EB5>鎴愬姛
鈫?
琛ㄦ牸鑷<E789B8>姩鍒锋柊锛屾柊澧?age_group"鍒?
鈫?
鐢ㄦ埛缁х画璇达細"鍒犻櫎鎵€鏈夌己澶辨偅鑰匢D鐨勮<E990A8>"
鈫?
AI鎵ц<E98EB5> 鈫?琛ㄦ牸鍒锋柊锛屾樉绀哄垹闄や簡23琛?
鈫?
鐢ㄦ埛鐐瑰嚮"瀵煎嚭"锛屼笅杞藉<E69D9E>鐞嗗悗鐨凟xcel
*鎴愬姛鏍囧噯锛?
- 鉁?鏁翠釜娴佺▼ < 2鍒嗛挓瀹屾垚
- 鉁?AI浠g爜涓€娆℃€ф墽琛屾垚鍔?
- 鉁?鐢ㄦ埛鏃犻渶鐪嬫枃妗e氨鑳芥搷浣?
浜屻€佹妧鏈<EFBFBD>灦鏋勬柟妗堬紙鍔″疄鐗堬級
2.1 鎬讳綋鏋舵瀯锛堢畝鍖栫増锛? 鈿狅笍 閲嶈<E996B2>锛氬<E9949B>鐢ㄥ钩鍙拌兘鍔?
鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈹? 鍓嶇<E98D93> (React) 鈹?
鈹? frontend-v2/src/modules/dc/pages/tool-c/ 鈹?
鈹? 鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹?
鈹? 鈹?AG Grid (70%) 鈹? 鈹?AI Chat Sidebar (30%) 鈹? 鈹?
鈹? 鈹?鈥?灞曠ず100琛屾暟鎹? 鈹? 鈹?鈥?鑷<>劧璇<E58AA7>█杈撳叆 鈹? 鈹?
鈹? 鈹?鈥?鍙<><E98D99>妯″紡鍒囨崲 鈹? 鈹?鈥?棰勬搷浣滃崱鐗? 鈹? 鈹?
鈹? 鈹?鈥?閿佸畾閬<E795BE>僵 鈹? 鈹?鈥?娑堟伅鍘嗗彶 鈹? 鈹?
鈹? 鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹?
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈫?REST API (JSON)
鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈹? Node.js鍚庣<E98D9A> (backend/src/modules/dc/tool-c/) 鈹?
鈹? 鈥?鏂囦欢涓婁紶锛堝<E9949B>鐢╯torage鏈嶅姟锛夆渽 鈹?
鈹? 鈥?浼氳瘽绠$悊锛堝瓨鏁版嵁搴擄紝涓嶇敤鍐呭瓨Map锛夆渽 鈹?
鈹? 鈥?LLM闆嗘垚锛堝<E9949B>鐢↙LMFactory锛夆渽 鈹?
鈹? 鈥?鏃ュ織璁板綍锛堝<E9949B>鐢╨ogger锛夆渽 鈹?
鈹? 鈥?寮傛<E5AFAE>浠诲姟锛堝<E9949B>鐢╦obQueue锛夆渽 鈹?
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈫?HTTP锛堝<E9949B>闇€Python鎵ц<E98EB5>锛?
鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈹? Python寰<6E>湇鍔★紙鍙<E7B499>€夛紝鎵╁睍鏂囨。澶勭悊寮曟搸锛? 鈹?
鈹? 鈥?DataFrame绠$悊锛堝瓨鏁版嵁搴擄紝涓嶇敤鍐呭瓨锛? 鈹?
鈹? 鈥?exec()浠g爜鎵ц<E98EB5> 鈹?
鈹? 鈥?AST闈欐€佸畨鍏ㄦ<E98D8F>鏌? 鈹?
鈹? 鈥?JSON搴忓垪鍖栬繑鍥? 鈹?
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈿狅笍 浜戝師鐢熸灦鏋勫己鍒惰<E98D92>姹傦細
- 鉁?澶嶇敤storage鏈嶅姟锛歚import { storage } from '@/common/storage'`
- 鉁?澶嶇敤logger鏈嶅姟锛歚import { logger } from '@/common/logging'`
- 鉁?澶嶇敤cache鏈嶅姟锛歚import { cache } from '@/common/cache'`
- 鉁?澶嶇敤LLMFactory锛歚import { LLMFactory } from '@/common/llm'`
- 鉁?澶嶇敤prisma瀹炰緥锛歚import { prisma } from '@/config/database'`
- 鉁?Session瀛樻暟鎹<EFBFBD>簱锛氫笉鐢ㄥ唴瀛楳ap锛堣繚鍙嶈<EFBFBD>鑼冿級
- 鉂?绂佹<EFBFBD>鏈<EFBFBD>湴鏂囦欢瀛樺偍锛欵xcel鐩存帴浠庡唴瀛樿В鏋?
- 鉂?绂佹<EFBFBD>鏂板缓Prisma瀹炰緥锛氫娇鐢ㄥ叏灞€瀹炰緥
*鍏抽敭鍐崇瓥锛?
- 鉁?涓嶇敤Apache Arrow锛欽SON澶熷揩锛?00琛?鈮?20KB锛?
- 鉁?Session瀛樻暟鎹<EFBFBD>簱锛氱<EFBFBD>鍚堜簯鍘熺敓瑙勮寖锛屾敮鎸佸<EFBFBD>瀹炰緥
- 鉁?涓嶅仛鎾ら攢锛氳妭鐪佸紑鍙戞椂闂达紝鐢ㄦ埛閲嶆柊涓婁紶鍗冲彲
- 鉁?**涓嶄繚鐣欐牱寮?*锛氱洿鎺ョ敓鎴愭柊Excel
2.2 鎶€鏈<E282AC>爤閫夊瀷锛堚渽 澶嶇敤鐜版湁鎶€鏈<E282AC>爤锛?
鍓嶇<EFBFBD>锛坒rontend-v2锛?
{
"framework": "React 19 + TypeScript 5 (宸叉湁)",
"table": "AG Grid Community (鍏嶈垂鐗?",
"ui": "Ant Design 5 (宸叉湁)",
"state": "React Query v5 (宸叉湁)",
"http": "axios (宸叉湁)",
"routing": "React Router DOM v6 (宸叉湁)"
}
Node.js鍚庣<E98D9A>锛坆ackend锛?
{
"framework": "Fastify v4 (宸叉湁)",
"llm": "鉁?澶嶇敤 LLMFactory (骞冲彴閫氱敤鑳藉姏灞?",
"storage": "鉁?澶嶇敤 storage鏈嶅姟 (骞冲彴鍩虹<E98DA9>灞?",
"logging": "鉁?澶嶇敤 logger鏈嶅姟 (骞冲彴鍩虹<E98DA9>灞?",
"cache": "鉁?澶嶇敤 cache鏈嶅姟 (骞冲彴鍩虹<E98DA9>灞?",
"database": "鉁?澶嶇敤 prisma鍏ㄥ眬瀹炰緥 (骞冲彴鍩虹<E98DA9>灞?",
"session": "鉁?PostgreSQL (dc_tool_c_sessions琛?",
"excel": "xlsx 搴擄紙鍐呭瓨瑙f瀽锛?,
"validation": "Joi"
}
Python寰<EFBFBD>湇鍔★紙鈿狅笍 鏍稿績鍔熻兘锛屾墿灞曠幇鏈夋湇鍔★級猸愨瓙猸愨瓙猸?
鍐崇瓥锛氣渽 绯荤粺宸叉湁Python寰<EFBFBD>湇鍔★紙FastAPI锛夛紝闇€鎵╁睍浠g爜鎵ц<EFBFBD>鍔熻兘
馃摝 鐜版湁Python鏈嶅姟锛堝凡瀹屾垚锛夛細
- 鉁?extraction_service锛欶astAPI + PyMuPDF + Pandas + openpyxl
- 鉁?绔<EFBFBD>彛锛?000锛堝凡杩愯<E69DA9>锛?
- 鉁?鍔熻兘锛歅DF/Docx/Txt鏂囨。鎻愬彇銆佽<E98A86>瑷€妫€娴?
- 鉁?闆嗘垚锛歂ode.js閫氳繃ExtractionClient璋冪敤
- 鉁?渚濊禆锛歅andas銆乷penpyxl銆乧hardet銆乴angdetect锛堝凡瀹夎<EFBFBD>锛?
馃敡 宸ュ叿C闇€瑕佺殑鏂板姛鑳斤細
| 鍔熻兘 | 鐜版湁鏈嶅姟 | 闇€姹? | 鏂规<EFBFBD> |
|---|---|---|---|
| Pandas浠g爜鎵ц<EFBFBD> | 鉂?涓嶆敮鎸? | 鉁?鏍稿績 | 鏂板<EFBFBD>API绔<EFBFBD>偣 /api/dc/execute |
| Excel涓婁紶 | 鉂?涓嶆敮鎸? | 鉁?闇€瑕? | 澶嶇敤MultiPart涓婁紶 |
| DataFrame绠$悊 | 鉂?涓嶆敮鎸? | 鉁?浼氳瘽 | 鏂板<EFBFBD>Session绠$悊 |
| *AST浠g爜妫€鏌? | 鉂?涓嶆敮鎸? | 鉁?蹇呴』 | 鏂板<EFBFBD>AST妯″潡 |
| Excel瀵煎嚭 | 鉂?涓嶆敮鎸? | 鉁?闇€瑕? | 浣跨敤openpyxl锛堝凡瀹夎<EFBFBD>锛? |
鈿狅笍 涓嶉渶瑕侀噸澶嶅紑鍙戯細
- 鉂?涓嶉渶瑕佹柊寤篜ython椤圭洰
- 鉂?涓嶉渶瑕侀噸鏂板畨瑁匬andas/openpyxl锛堝凡瀹夎<E780B9>锛?
- 鉂?涓嶉渶瑕侀噸鏂伴厤缃瓼astAPI锛堝凡杩愯<E69DA9>锛?
- 鉂?涓嶉渶瑕侀噸鏂板啓Node.js璋冪敤閫昏緫锛圗xtractionClient宸插瓨鍦<E793A8>級
*鉁?MVP鎵╁睍鏂规<E98F82>锛?
# extraction_service/services/dc_executor.py锛堟柊澧烇級
import pandas as pd
import ast
from typing import Dict, Any
def validate_code(code: str) -> Dict[str, Any]:
"""AST闈欐€佹<E282AC>鏌ワ紙瀹夊叏楠岃瘉锛?""
try:
tree = ast.parse(code)
# 绂佹<E7BB82>import os銆乻ys銆乻ubprocess绛?
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
if alias.name in ['os', 'sys', 'subprocess', 'socket']:
return {'valid': False, 'error': f'绂佹<E7BB82>瀵煎叆{alias.name}'}
return {'valid': True}
except Exception as e:
return {'valid': False, 'error': str(e)}
def execute_pandas_code(data: list, code: str) -> Dict[str, Any]:
"""鎵ц<EFBFBD>Pandas浠g爜锛堚瓙鏍稿績鍔熻兘锛?""
try:
# 1. 瀹夊叏妫€鏌?
validation = validate_code(code)
if not validation['valid']:
return {'success': False, 'error': validation['error']}
# 2. 鍔犺浇鏁版嵁
df = pd.DataFrame(data)
# 3. 鎵ц<E98EB5>浠g爜锛堟敞鍏<E6959E>f鍜宲d锛?
exec(code, {'df': df, 'pd': pd})
# 4. 杩斿洖缁撴灉锛堝墠100琛岋級
return {
'success': True,
'data': df.head(100).to_dict('records'),
'totalRows': len(df),
'totalCols': len(df.columns),
'columns': df.columns.tolist()
}
except Exception as e:
return {'success': False, 'error': str(e)}
# extraction_service/main.py锛堟墿灞曪級
from services.dc_executor import execute_pandas_code, validate_code
@app.post("/api/dc/execute")
async def execute_code(
data: List[Dict],
code: str
):
"""宸ュ叿C锛氭墽琛孭andas浠g爜"""
result = execute_pandas_code(data, code)
return JSONResponse(result)
@app.post("/api/dc/validate")
async def validate_code_endpoint(code: str):
"""宸ュ叿C锛欰ST浠g爜妫€鏌?""
result = validate_code(code)
return JSONResponse(result)
鉁?Node.js璋冪敤锛堝<E9949B>鐢‥xtractionClient妯″紡锛夛細
// backend/src/modules/dc/tool-c/services/PythonExecutorService.ts
import axios from 'axios';
const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
export class PythonExecutorService {
async executeCode(data: any[], code: string) {
const response = await axios.post(`${EXTRACTION_SERVICE_URL}/api/dc/execute`, {
data,
code
});
return response.data;
}
}
2.3 鏁版嵁娴佽<E5A8B4>璁?
*浼氳瘽鐢熷懡鍛ㄦ湡锛?
# 1. 鐢ㄦ埛涓婁紶鏂囦欢
POST /api/tool-c/session/init
{
file: File,
userId: string
}
# Node.js: 杞<>彂鍒癙ython
# Python:
# - 璇诲彇Excel 鈫?DataFrame
# - 瀛樺叆鍐呭瓨锛歴essions[sessionId] = df
# - 杩斿洖锛歴essionId + 鏁版嵁姒傝<E5A792>
# 2. 鐢ㄦ埛鍙戦€丄I鎸囦护
POST /api/tool-c/ai/execute
{
sessionId: string,
prompt: string
}
# Node.js:
# - 鏋勫缓System Prompt锛堝寘鍚<E5AF98>暟鎹<E69A9F>笂涓嬫枃锛?
# - 璋冪敤LLM鐢熸垚浠g爜
# - 杞<>彂浠g爜鍒癙ython
# Python:
# - AST妫€鏌?
# - exec(code)淇<>敼df
# - 杩斿洖鍓?00琛孞SON
# 3. 鐢ㄦ埛瀵煎嚭
GET /api/tool-c/session/export/{sessionId}
# Python:
# - df.to_excel(buffer)
# - 杩斿洖浜岃繘鍒舵祦
涓夈€佸姛鑳戒紭鍏堢骇鐭╅樀
3.1 P0绾э細蹇呴』寮€鍙戯紙鏍稿績闂<E7B8BE>幆锛夆瓙猸愨瓙猸愨瓙
| ID | 鍔熻兘 | 鎻忚堪 | 楠岃瘉鐩<EFBFBD>爣 | 宸ユ椂 | 璐熻矗浜? |
|---|---|---|---|---|---|
| P0-001 | 鏂囦欢涓婁紶 | 鍓嶇<EFBFBD>Upload缁勪欢 + 10MB闄愬埗 | 鑳藉惁瑙f瀽Excel | 0.5澶? | 鍓嶇<EFBFBD> |
| P0-002 | Session鍒濆<EFBFBD>鍖? | 鍚庣<EFBFBD>鎺ユ敹鏂囦欢锛孭ython鍔犺浇DataFrame | 涓<EFBFBD>枃鍒楀悕銆丟BK缂栫爜 | 1澶? | 鍚庣<EFBFBD> |
| P0-003 | 琛ㄦ牸灞曠ず | AG Grid灞曠ず100琛屾暟鎹? | 鍒楃被鍨嬭瘑鍒<EFBFBD>€佺┖鍊奸珮浜? | 1澶? | 鍓嶇<EFBFBD> |
| P0-004 | AI瀵硅瘽UI | 鍙充晶渚ц竟鏍忥紝娑堟伅鍒楄〃 | 鑱婂ぉ浜や簰娴佺晠 | 0.5澶? | 鍓嶇<EFBFBD> |
| P0-005 | System Prompt鏋勫缓 | 鍖呭惈鏁版嵁涓婁笅鏂囩殑Prompt | AI鑳界悊瑙f暟鎹<EFBFBD>粨鏋? | 1澶? | 鍚庣<EFBFBD> |
| P0-006 | AI浠g爜鐢熸垚 | 璋冪敤DeepSeek-V3鐢熸垚Pandas浠g爜 | 鎴愬姛鐜?80% | 2澶? | 鍚庣<EFBFBD> |
| P0-007 | AST瀹夊叏妫€鏌? | 鎷︽埅鍗遍櫓浠g爜 | import os琚<EFBFBD>嫤鎴? |
1澶? | Python |
| P0-008 | 浠g爜鎵ц<EFBFBD> | exec()鍦ㄦ矙绠变腑杩愯<E69DA9>浠g爜 | 淇<EFBFBD>敼DataFrame鎴愬姛 | 1澶? | Python |
| P0-009 | 棰勬搷浣滃崱鐗? | 灞曠ず浠g爜锛岀敤鎴风‘璁ゅ悗鎵ц<EFBFBD> | 鐢ㄦ埛鑳界湅鎳備唬鐮佹剰鍥? | 0.5澶? | 鍓嶇<EFBFBD> |
| P0-010 | 琛ㄦ牸鍒锋柊 | 鎵ц<EFBFBD>鍚庤嚜鍔ㄦ媺鍙栨柊鏁版嵁 | 鍓嶇<EFBFBD>瀹炴椂鏇存柊 | 0.5澶? | 鍓嶇<EFBFBD> |
| P0-011 | UI閿佸畾鏈哄埗 | AI澶勭悊鏃惰〃鏍煎彉鐏?閬<>僵 | 鐗╃悊绂佹<EFBFBD>骞跺彂鎿嶄綔 | 0.5澶? | 鍓嶇<EFBFBD> |
| P0-012 | 瀵煎嚭Excel | 涓嬭浇澶勭悊鍚庣殑鏂囦欢 | 鏂囦欢瀹屾暣鎬? | 1澶? | Python |
*P0灏忚<EFBFBD>锛?1.5澶?
3.2 P1绾э細蹇呴』楠岃瘉锛屽彲绠€鍖栧疄鐜?猸愨瓙猸愨瓙
| ID | 鍔熻兘 | MVP绠€鍖栨柟妗? | 瀹屾暣鐗? | 宸ユ椂 |
|---|---|---|---|---|
| P1-001 | 浼氳瘽绠$悊 | 杩涚▼鍐呭瓨Map锛堝崟瀹炰緥锛? | Redis鍒嗗竷寮? | 0.5澶? |
| P1-002 | 蹇冭烦淇濇椿 | 鍥哄畾10鍒嗛挓杩囨湡锛屼笉缁<EFBFBD>湡 | 鍓嶇<EFBFBD>蹇冭烦缁<EFBFBD>湡 | 0.5澶? |
| P1-003 | 缂栫爜妫€娴? | chardet鑷<EFBFBD>姩妫€娴?鍙嬪ソ鎶ラ敊 | 鑷<EFBFBD>姩杞<EFBFBD>崲 | 1澶? |
| P1-004 | AI鑷<EFBFBD>垜淇<EFBFBD><EFBFBD> | 澶辫触鍚庨噸璇?娆? | 澶氭<EFBFBD>閲嶈瘯+瀛︿範 | 1澶? |
| P1-005 | 蹇<EFBFBD>嵎妯℃澘 | 3涓<EFBFBD>父鐢ㄦā鏉匡紙骞撮緞鍒嗙粍绛夛級 | 10+妯℃澘搴? | 0.5澶? |
*P1灏忚<EFBFBD>锛?.5澶?
3.3 P2绾э細寤跺悗鎴栦笉鍋?猸愨瓙
| 鍔熻兘 | 寤跺悗鍘熷洜 | 浣曟椂鍋? |
|---|---|---|
| 鎵嬪姩缂栬緫鍗曞厓鏍? | MVP涓撴敞AI | P2闃舵<EFBFBD> |
| 鎾ら攢/鍥炴粴 | 鑺傜渷鍐呭瓨 | P2闃舵<EFBFBD> |
| Apache Arrow | JSON澶熺敤 | 鎬ц兘涓嶈揪鏍囨椂 |
| Redis鍒嗗竷寮? | 鍗曞疄渚嬪<EFBFBD>鐢? | 妯<EFBFBD>悜鎵╁睍鏃? |
| 鏍峰紡淇濈暀 | 澶嶆潅搴﹂珮 | P3闃舵<EFBFBD> |
| 鎿嶄綔瀹¤<EFBFBD> | 闈炴牳蹇? | P3闃舵<EFBFBD> |
| 澶歋heet鏀<EFBFBD>寔 | 绠€鍖栭€昏緫 | P3闃舵<EFBFBD> |
鍥涖€?鍛ㄨ<E98D9B>缁嗗紑鍙戣<E98D99>鍒?
Week 1锛氬熀纭€鏋舵瀯鎼<E780AF>缓锛?澶╋級
Day 1锛氱幆澧冩惌寤?+ 浠g爜缁撴瀯锛堚殸锔?鍙傝€僼ool-b缁撴瀯 + Python鐜<6E><E9909C>锛?
*浠诲姟娓呭崟锛?
-
鍒涘缓椤圭洰鐩<EFBFBD>綍缁撴瀯锛?*鍙傝€僼ool-b**锛?
backend/src/modules/dc/tool-c/ 鈫?涓荤洰褰? 鈹溾攢鈹€ services/ 鈫?涓氬姟閫昏緫灞? 鈹? 鈹溾攢鈹€ SessionService.ts 鈫?Session绠$悊锛堝瓨鏁版嵁搴擄級 鈹? 鈹溾攢鈹€ AICodeService.ts 鈫?AI浠g爜鐢熸垚 鈹? 鈹溾攢鈹€ PythonExecutorService.ts 鈫?猸?Python浠g爜鎵ц<E98EB5>锛堟牳蹇冿級 鈹? 鈹斺攢鈹€ DataProcessService.ts 鈫?鏁版嵁澶勭悊閫昏緫 鈹溾攢鈹€ controllers/ 鈫?鎺у埗鍣ㄥ眰 鈹? 鈹斺攢鈹€ ToolCController.ts 鈫?HTTP璇锋眰澶勭悊 鈹溾攢鈹€ routes/ 鈫?璺<>敱灞? 鈹? 鈹斺攢鈹€ index.ts 鈫?璺<>敱瀹氫箟 鈹斺攢鈹€ utils/ 鈫?宸ュ叿鍑芥暟 鈹溾攢鈹€ codeValidator.ts 鈫?AST浠g爜妫€鏌? 鈹斺攢鈹€ pythonScripts/ 鈫?猸?Python鎵ц<E98EB5>鑴氭湰 鈹斺攢鈹€ executor.py 鈫?Pandas浠g爜鎵ц<E98EB5>鍣? frontend-v2/src/modules/dc/pages/tool-c/ 鈫?鍓嶇<E98D93>锛堝凡瀛樺湪锛? -
猸?鎵╁睍鐜版湁Python鏈嶅姟锛堟牳蹇冨姛鑳斤級
# 绯荤粺宸叉湁Python寰<6E>湇鍔★紙extraction_service锛夛紝鍙<E7B49D>渶鎵╁睍鍔熻兘 cd extraction_service # 1. 鍒涘缓DC鎵ц<E98EB5>鍣ㄦā鍧? cat > services/dc_executor.py << 'EOF' import pandas as pd import ast from typing import Dict, Any, List def validate_code(code: str) -> Dict[str, Any]: """AST闈欐€佹<E282AC>鏌ワ紙瀹夊叏楠岃瘉锛?"" try: tree = ast.parse(code) # 绂佹<E7BB82>鍗遍櫓瀵煎叆 forbidden_modules = ['os', 'sys', 'subprocess', 'socket', 'shutil', 'requests'] for node in ast.walk(tree): if isinstance(node, ast.Import): for alias in node.names: if alias.name in forbidden_modules: return {'valid': False, 'error': f'绂佹<E7BB82>瀵煎叆{alias.name}妯″潡'} elif isinstance(node, ast.ImportFrom): if node.module in forbidden_modules: return {'valid': False, 'error': f'绂佹<E7BB82>瀵煎叆{node.module}妯″潡'} return {'valid': True} except Exception as e: return {'valid': False, 'error': f'浠g爜璇<E7889C>硶閿欒<E996BF>: {str(e)}'} def execute_pandas_code(data: List[Dict], code: str) -> Dict[str, Any]: """鎵ц<E98EB5>Pandas浠g爜锛堚瓙鏍稿績鍔熻兘锛?"" try: # 1. 瀹夊叏妫€鏌? validation = validate_code(code) if not validation['valid']: return {'success': False, 'error': validation['error']} # 2. 鍔犺浇鏁版嵁鍒癉ataFrame df = pd.DataFrame(data) # 3. 鎵ц<E98EB5>浠g爜锛堟敞鍏<E6959E>f鍜宲d锛岄殧绂荤幆澧冿級 local_env = {'df': df, 'pd': pd} exec(code, {'__builtins__': {}}, local_env) # 4. 鑾峰彇鎵ц<E98EB5>鍚庣殑df df_result = local_env.get('df', df) # 5. 杩斿洖缁撴灉锛堝墠100琛岋紝閬垮厤鏁版嵁閲忚繃澶э級 return { 'success': True, 'data': df_result.head(100).to_dict('records'), 'totalRows': len(df_result), 'totalCols': len(df_result.columns), 'columns': df_result.columns.tolist() } except Exception as e: return { 'success': False, 'error': f'浠g爜鎵ц<E98EB5>澶辫触: {str(e)}' } EOF # 2. 鎵╁睍main.py锛屾坊鍔燚C绔<43>偣 # 鍦╩ain.py鏈<79>熬娣诲姞锛? cat >> main.py << 'EOF' # ==================== DC宸ュ叿C绔<43>偣 ==================== from services.dc_executor import execute_pandas_code, validate_code from pydantic import BaseModel class ExecuteRequest(BaseModel): data: List[Dict] code: str class ValidateRequest(BaseModel): code: str @app.post("/api/dc/execute") async def dc_execute_code(request: ExecuteRequest): """宸ュ叿C锛氭墽琛孭andas浠g爜""" logger.info(f"DC Execute: code length={len(request.code)}, data rows={len(request.data)}") result = execute_pandas_code(request.data, request.code) return JSONResponse(result) @app.post("/api/dc/validate") async def dc_validate_code(request: ValidateRequest): """宸ュ叿C锛欰ST浠g爜妫€鏌?"" logger.info(f"DC Validate: code length={len(request.code)}") result = validate_code(request.code) return JSONResponse(result) EOF -
*Node.js璋冪敤Python鏈嶅姟锛圥ythonExecutorService锛?
// backend/src/modules/dc/tool-c/services/PythonExecutorService.ts import axios from 'axios'; import { logger } from '@/common/logging'; const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000'; export interface ExecuteResult { success: boolean; data?: any[]; totalRows?: number; totalCols?: number; columns?: string[]; error?: string; } export class PythonExecutorService { private baseUrl: string; constructor() { this.baseUrl = EXTRACTION_SERVICE_URL; } /** * 鎵ц<E98EB5>Pandas浠g爜锛堚瓙 鏍稿績鍔熻兘锛? * 澶嶇敤鐜版湁Python寰<6E>湇鍔★紝娣诲姞鏂扮<E98F82>鐐? */ async executeCode(data: any[], code: string): Promise<ExecuteResult> { try { logger.info('Calling Python executor', { dataRows: data.length, codeLength: code.length }); const response = await axios.post<ExecuteResult>( `${this.baseUrl}/api/dc/execute`, { data, code }, { timeout: 30000 } // 30绉掕秴鏃? ); logger.info('Python execution success', { totalRows: response.data.totalRows }); return response.data; } catch (error) { logger.error('Python execution failed', { error }); if (axios.isAxiosError(error) && error.response) { throw new Error(error.response.data.error || 'Python execution failed'); } throw new Error('鏃犳硶杩炴帴鍒癙ython鎵ц<E98EB5>鏈嶅姟'); } } /** * AST浠g爜妫€鏌ワ紙鎵ц<E98EB5>鍓嶉獙璇侊級 */ async validateCode(code: string): Promise<{ valid: boolean; error?: string }> { try { const response = await axios.post( `${this.baseUrl}/api/dc/validate`, { code }, { timeout: 5000 } ); return response.data; } catch (error) { logger.error('Code validation failed', { error }); throw new Error('浠g爜楠岃瘉澶辫触'); } } } export const pythonExecutorService = new PythonExecutorService(); -
**寮哄埗妫€鏌?*锛氱‘淇濆<E6B787>鐢ㄥ钩鍙版湇鍔?
// backend/src/modules/dc/tool-c/services/SessionService.ts // 鉁?蹇呴』瀵煎叆杩欎簺骞冲彴鏈嶅姟 import { storage } from '@/common/storage'; import { logger } from '@/common/logging'; import { cache } from '@/common/cache'; import { prisma } from '@/config/database'; // 鉂?绂佹<E7BB82>鑷<EFBFBD>繁瀹炵幇 // const sessions = new Map() 鈫?杩濆弽瑙勮寖锛? -
鏁版嵁搴揝chema璁捐<EFBFBD>锛坉c_schema锛?
// prisma/schema.prisma锛堟坊鍔犲埌dc_schema锛? model DcToolCSession { id String @id @default(uuid()) userId String sessionId String @unique fileName String dataSnapshot Json // 瀛樺偍100琛岄<E7909B>瑙堟暟鎹? totalRows Int totalCols Int columns Json // 鍒椾俊鎭? expiresAt DateTime // 10鍒嗛挓杩囨湡 createdAt DateTime @default(now()) @@schema("dc_schema") @@map("dc_tool_c_sessions") }
*楠屾敹鏍囧噯锛?
- 鉁?鏂囦欢澶圭粨鏋勪笌tool-b涓€鑷?
- 鉁?瀵煎叆浜嗘墍鏈夊繀椤荤殑骞冲彴鏈嶅姟
- 鉁?娌℃湁鍐呭瓨Map銆佹病鏈夋湰鍦版枃浠跺瓨鍌?
璐熻矗浜猴細 鍚庣<E98D9A>寮€鍙?
Day 2锛歋ession绠$悊 + 鏁版嵁鍔犺浇锛堚殸锔?瀛樻暟鎹<E69A9F>簱锛屼笉鐢ㄥ唴瀛橈級
*浠诲姟娓呭崟锛?
- 瀹炵幇SessionService锛?*瀛樻暟鎹<E69A9F>簱锛岀<E9949B>鍚堜簯鍘熺敓瑙勮寖**锛?
// backend/src/modules/dc/tool-c/services/SessionService.ts import { storage } from '@/common/storage'; import { logger } from '@/common/logging'; import { prisma } from '@/config/database'; import * as xlsx from 'xlsx'; import chardet from 'chardet'; export class SessionService { /** * 鍒涘缓Session锛堚渽 瀛樻暟鎹<E69A9F>簱锛屼笉鐢ㄥ唴瀛楳ap锛? */ async createSession(userId: string, fileBuffer: Buffer, fileName: string): Promise<string> { // 1. 妫€娴嬬紪鐮? const detected = chardet.detect(fileBuffer); if (detected.encoding.toLowerCase() !== 'utf-8') { throw new Error(`鏂囦欢缂栫爜涓?{detected.encoding}锛岃<E9949B>杞<EFBFBD>崲涓篣TF-8`); } // 2. 鍐呭瓨瑙f瀽Excel锛堚渽 浜戝師鐢燂細涓嶈惤鐩橈級 const workbook = xlsx.read(fileBuffer, { type: 'buffer' }); const sheet = workbook.Sheets[workbook.SheetNames[0]]; const data = xlsx.utils.sheet_to_json(sheet); // 3. 鎻愬彇鍒椾俊鎭? const columns = Object.keys(data[0] || {}).map(col => ({ name: col, type: typeof data[0][col] })); // 4. Session瀛樻暟鎹<E69A9F>簱锛堚渽 绗﹀悎浜戝師鐢熻<E990A2>鑼冿級 const sessionId = `session_${Date.now()}_${Math.random().toString(36)}`; await prisma.dcToolCSession.create({ data: { sessionId, userId, fileName, dataSnapshot: data.slice(0, 100), // 鍙<>瓨鍓?00琛岄<E7909B>瑙? totalRows: data.length, totalCols: columns.length, columns, expiresAt: new Date(Date.now() + 10 * 60 * 1000) // 10鍒嗛挓杩囨湡 } }); // 5. 瀹屾暣鏁版嵁涓婁紶鍒癘SS锛堚渽 浜戝師鐢燂細鎸佷箙鍖栧瓨鍌<E793A8>級 const dataKey = `dc/tool-c/${sessionId}/full-data.json`; await storage.uploadBuffer(dataKey, Buffer.from(JSON.stringify(data))); logger.info('Session created', { sessionId, totalRows: data.length }); return sessionId; } /** * 鑾峰彇Session锛堜粠鏁版嵁搴撹<E690B4>鍙栵級 */ async getSession(sessionId: string) { const session = await prisma.dcToolCSession.findUnique({ where: { sessionId } }); if (!session || new Date() > session.expiresAt) { throw new Error('Session宸茶繃鏈?); } return session; } }
*娴嬭瘯鐢ㄤ緥锛?
- 涓婁紶UTF-8缂栫爜鐨凟xcel锛屾<E9949B>甯歌В鏋?
- 涓婁紶GBK缂栫爜鐨凟xcel锛岃<EFBFBD>鎷︽埅骞舵彁绀?
- 涓婁紶涓<EFBFBD>枃鍒楀悕鐨凟xcel锛屾棤涔辩爜
- Session瀛樺叆鏁版嵁搴擄紝鍙<EFBFBD>煡璇?
- 10鍒嗛挓鍚嶴ession鑷<EFBFBD>姩杩囨湡
*楠屾敹鏍囧噯锛?
- 鉁?Session瀛樺偍鍦ㄦ暟鎹<E69A9F>簱锛堜笉鏄<E7AC89>唴瀛楳ap锛?
- 鉁?瀹屾暣鏁版嵁瀛樺偍鍦∣SS
- 鉁?绗﹀悎浜戝師鐢熷紑鍙戣<E98D99>鑼?
璐熻矗浜猴細 Node.js鍚庣<E98D9A>
Day 3锛歂ode.js BFF + 鏂囦欢涓婁紶
*浠诲姟娓呭崟锛?
- 鍒涘缓Fastify璺<EFBFBD>敱
// backend/src/modules/dc/tool-c/routes/index.ts import { FastifyInstance } from 'fastify'; export async function registerToolCRoutes(fastify: FastifyInstance) { // 鏂囦欢涓婁紶 fastify.post('/api/v1/dc/tool-c/session/init', async (req, reply) => { const file = await req.file(); // 1. 鏂囦欢澶у皬妫€鏌? if (file.file.bytesRead > 10 * 1024 * 1024) { return reply.code(413).send({ success: false, error: '鏂囦欢杩囧ぇ锛岃<E9949B>鍘嬬缉鍚庨噸璇曪紙闄?0MB锛? }); } // 2. 杞<>彂鍒癙ython鏈嶅姟 const formData = new FormData(); formData.append('file', file.file, file.filename); const response = await axios.post('http://localhost:8001/api/python/init', formData); return { success: true, sessionId: response.data.sessionId, data: response.data }; }); } - 闆嗘垚鍒颁富搴旂敤
// backend/src/modules/dc/index.ts import { registerToolCRoutes } from './tool-c/routes'; export async function registerDCRoutes(fastify: FastifyInstance) { await registerToolBRoutes(fastify); await registerToolCRoutes(fastify); // 鏂板<E98F82> }
*娴嬭瘯鐢ㄤ緥锛?
- 涓婁紶9MB鏂囦欢锛屾垚鍔?
- 涓婁紶11MB鏂囦欢锛岃<EFBFBD>鎷︽埅
- 骞跺彂涓婁紶2涓<EFBFBD>枃浠讹紝sessionId涓嶅啿绐?
*楠屾敹鏍囧噯锛?
- 鉁?Node.js鑳芥<E991B3>纭<EFBFBD>浆鍙戞枃浠跺埌Python
- 鉁?鏂囦欢澶у皬闄愬埗鐢熸晥
璐熻矗浜猴細 Node.js鍚庣<E98D9A>
Day 4锛氬墠绔<E5A2A0><E7BB94>鏋舵惌寤?
*浠诲姟娓呭崟锛?
- 鍒涘缓Tool C椤甸潰
// frontend-v2/src/modules/dc/pages/tool-c/index.tsx import { AgGridReact } from 'ag-grid-react'; import { Upload, Spin } from 'antd'; export default function ToolCEditor() { const [sessionId, setSessionId] = useState<string>(); const [data, setData] = useState<any[]>([]); const [columns, setColumns] = useState<any[]>([]); const [isLoading, setIsLoading] = useState(false); const handleUpload = async (file: File) => { setIsLoading(true); const formData = new FormData(); formData.append('file', file); const response = await api.post('/api/v1/dc/tool-c/session/init', formData); setSessionId(response.data.sessionId); setData(response.data.data.preview); setColumns(response.data.data.columns); setIsLoading(false); }; return ( <div className="h-screen flex"> {/* 宸︿晶锛氳〃鏍煎尯鍩?*/} <div className="flex-1"> {!sessionId ? ( <Upload beforeUpload={handleUpload}> <Button>涓婁紶Excel鏂囦欢锛堥檺10MB锛?/Button> </Upload> ) : ( <AgGridReact rowData={data} columnDefs={columns.map(col => ({ field: col.name, headerName: col.name }))} /> )} </div> {/* 鍙充晶锛欰I渚ц竟鏍忥紙鍗犱綅锛?*/} <div className="w-96 border-l bg-white"> <h3>AI鍔╂墜</h3> </div> </div> ); } - 闆嗘垚AG Grid
cd frontend-v2 npm install ag-grid-react ag-grid-community - 璺<EFBFBD>敱閰嶇疆
// frontend-v2/src/modules/dc/routes.tsx { path: 'tool-c', element: <ToolCEditor /> }
*娴嬭瘯鐢ㄤ緥锛?
- 涓婁紶鏂囦欢锛岃〃鏍兼<EFBFBD>纭<EFBFBD>樉绀?
- 涓<EFBFBD>枃鍒楀悕鏄剧ず姝e父
- 绌哄€煎崟鍏冩牸鏈夎<EFBFBD>瑙夋彁绀?
*楠屾敹鏍囧噯锛?
- 鉁?鐢ㄦ埛鑳界湅鍒板乏鍙冲垎鏍忕晫闈?
- 鉁?琛ㄦ牸鑳藉睍绀?00琛屾暟鎹?
璐熻矗浜猴細 鍓嶇<E98D93>寮€鍙?
Day 5锛歋ystem Prompt鏋勫缓
*浠诲姟娓呭崟锛?
- 鍒涘缓Prompt妯℃澘
// backend/src/modules/dc/tool-c/prompts/system-prompt.ts export function buildSystemPrompt(dataContext: DataContext): string { return `# AI鍖荤枟鏁版嵁娓呮礂鍔╂墜 - 绯荤粺瑙掕壊
褰撳墠鏁版嵁缁撴瀯
- 鎬昏<EFBFBD>鏁帮細${dataContext.totalRows} 琛?
- 鎬诲垪鏁帮細${dataContext.totalCols} 鍒?
- 鍒楀悕锛?{dataContext.columns.map(c => c.name).join(', ')}
鍓?琛屾暟鎹<E69A9F>ず渚?
${JSON.stringify(dataContext.headData, null, 2)}
涓ユ牸瑙勫垯
- 鍙<EFBFBD>兘浣跨敤pandas鎿嶄綔锛堝凡棰勫<EFBFBD>鍏ヤ负pd锛?
- 鍙橀噺鍚嶅繀椤绘槸df锛堜笉瑕佺敤鍏朵粬鍚嶅瓧锛?
- 灏卞湴淇<EFBFBD>敼锛歞f['new'] = ... 鎴?df.drop(...)
- 涓嶈<EFBFBD>print()銆乨isplay()绛夎緭鍑?
- 绂佹<EFBFBD>import os銆乻ys銆乺equests绛?
Few-shot绀轰緥锛堝垎灞傞毦搴︼細鍩虹<E98DA9>鈫掍腑绛夆啋楂樼骇锛?
馃煝 鍩虹<E98DA9>鍦烘櫙锛堝崟姝ラ<E5A79D>鎿嶄綔锛?
鍦烘櫙1锛氬勾榫勫垎缁?
鐢ㄦ埛锛?鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁? 浠g爜锛? df['age_group'] = df['age'].apply(lambda x: '鑰佸勾缁? if pd.notna(x) and x > 60 else '闈炶€佸勾缁?)
鍦烘櫙2锛氬垹闄ょ己澶?
鐢ㄦ埛锛?鍒犻櫎娌℃湁鎮h€匢D鐨勮<E990A8>" 浠g爜锛? df.dropna(subset=['patient_id'], inplace=True)
鍦烘櫙3锛氭€у埆缂栫爜
鐢ㄦ埛锛?鎶婃€у埆杞<E59F86>负鏁板瓧" 浠g爜锛? df['gender_code'] = df['gender'].map({'鐢?: 1, '濂?: 0})
馃煛 涓<>瓑鍦烘櫙锛堝<E9949B>姝ラ<E5A79D>鎴栬法鍒楅€昏緫锛?
鍦烘櫙4锛氳<EFBFBD>绠桸LR骞跺垎缁?
鐢ㄦ埛锛?璁$畻涓<E795BB>€х矑缁嗚優娣嬪反缁嗚優姣斿€糔LR锛屽苟鎸?.5鍒嗕负楂樹綆涓ょ粍" 浠g爜锛? df['NLR'] = df.apply(lambda row: row['neutrophil'] / row['lymphocyte'] if pd.notna(row['neutrophil']) and pd.notna(row['lymphocyte']) and row['lymphocyte'] > 0 else None, axis=1) df['NLR_group'] = df['NLR'].apply(lambda x: 'High' if pd.notna(x) and x > 2.5 else 'Low')
鍦烘櫙5锛氬瓧绗︿覆鎷嗗垎锛堣<EFBFBD>鍘嬶級
鐢ㄦ埛锛?鎶婅<E98EB6>鍘嬪垪鐨?120/80'鏍煎紡鎷嗗垎鎴愭敹缂╁帇鍜岃垝寮犲帇锛屽苟鍒ゆ柇鏄<E69F87>惁楂樿<E6A582>鍘? 浠g爜锛? df'systolic_bp', 'diastolic_bp' = df['blood_pressure'].str.split('/', expand=True) df['systolic_bp'] = pd.to_numeric(df['systolic_bp'], errors='coerce') df['diastolic_bp'] = pd.to_numeric(df['diastolic_bp'], errors='coerce') df['is_hypertension'] = ((df['systolic_bp'] > 140) | (df['diastolic_bp'] > 90)).astype(int)
鍦烘櫙6锛氭椂闂村樊璁$畻锛堥€昏緫楠岃瘉锛?
鐢ㄦ埛锛?璁$畻浣忛櫌澶╂暟锛屽<E9949B>鏋滃嚭闄㈡棩鏈熸棭浜庡叆闄㈡棩鏈熷垯鏍囪<E98F8D>涓哄紓甯? 浠g爜锛? df['admission_date'] = pd.to_datetime(df['admission_date'], errors='coerce') df['discharge_date'] = pd.to_datetime(df['discharge_date'], errors='coerce') df['hospital_days'] = (df['discharge_date'] - df['admission_date']).dt.days df['date_error'] = df['hospital_days'] < 0 df.loc[df['date_error'], 'hospital_days'] = None
馃敶 楂樼骇鍦烘櫙锛堝垎缁勮仛鍚堛€佹椂闂村簭鍒椼€佸尰瀛﹁<E7809B>鍒欙級
鍦烘櫙7锛氱敓瀛樻椂闂磋<EFBFBD>绠楋紙澶嶆潅鏉′欢閫昏緫锛?
鐢ㄦ埛锛?鐢熸垚鐢熷瓨鐘舵€佸拰鐢熷瓨鏃堕棿锛屽<E9949B>鏋滄<E98F8B>浜℃棩鏈熷瓨鍦ㄥ垯鐘舵€佷负1锛屾椂闂翠负姝讳骸鏃ユ湡鍑忚瘖鏂<E79896>棩鏈燂紝鍚﹀垯鐘舵€佷负0锛屾椂闂翠负闅忚<E99785>鎴<EFBFBD><E98EB4>鏃ユ湡鍑忚瘖鏂<E79896>棩鏈? 浠g爜锛? df['diagnosis_date'] = pd.to_datetime(df['diagnosis_date'], errors='coerce') df['death_date'] = pd.to_datetime(df['death_date'], errors='coerce') df['followup_end_date'] = pd.to_datetime(df['followup_end_date'], errors='coerce') df['vital_status'] = df['death_date'].notna().astype(int) df['survival_days'] = df.apply(lambda row: (row['death_date'] - row['diagnosis_date']).days if pd.notna(row['death_date']) else (row['followup_end_date'] - row['diagnosis_date']).days, axis=1) df['survival_months'] = (df['survival_days'] / 30.44).round(1)
鍦烘櫙8锛氬垎缁勮仛鍚堬紙棣栨湯璁板綍锛?
鐢ㄦ埛锛?瀵规瘡涓<E798A1>偅鑰呮壘鍑虹<E98D91>涓€娆″寲鐤楁棩鏈熷拰鏈€鍚庝竴娆″寲鐤楁棩鏈燂紝璁$畻鎸佺画鏃堕棿" 浠g爜锛? df['chemo_date'] = pd.to_datetime(df['chemo_date'], errors='coerce') patient_chemo = df.groupby('patient_id')['chemo_date'].agg(['min', 'max']).reset_index() patient_chemo.columns = ['patient_id', 'first_chemo', 'last_chemo'] patient_chemo['chemo_duration_days'] = (patient_chemo['last_chemo'] - patient_chemo['first_chemo']).dt.days df = df.merge(patient_chemo'patient_id', 'first_chemo', 'last_chemo', 'chemo_duration_days', on='patient_id', how='left')
鍦烘櫙9锛氭椂闂村簭鍒楀彉鍖栫巼
鐢ㄦ埛锛?鎸夋偅鑰匢D鍒嗙粍锛岃<E9949B>绠楁瘡娆¢殢璁跨浉姣斾笂娆$殑鑲跨槫澶у皬鍙樺寲鐜? 浠g爜锛? df = df.sort_values(['patient_id', 'followup_date']) df['prev_tumor_size'] = df.groupby('patient_id')['tumor_size'].shift(1) df['tumor_change_rate'] = ((df['tumor_size'] - df['prev_tumor_size']) / df['prev_tumor_size'] * 100).round(2) df['tumor_change_rate'] = df['tumor_change_rate'].fillna(0)
鍦烘櫙10锛氬尰瀛﹁<EFBFBD>鍒欏紩鎿庯紙鑲濆姛鑳藉垎绾э級
鐢ㄦ埛锛?鏍规嵁ALT銆丄ST銆丄LP銆乀BIL鍒ゆ柇鑲濆姛鑳藉垎绾? 浠g爜锛? def classify_liver_function(row): abnormal_count = 0 if pd.notna(row.get('ALT')) and row['ALT'] > 40: abnormal_count += 1 if pd.notna(row.get('AST')) and row['AST'] > 40: abnormal_count += 1 if pd.notna(row.get('ALP')) and row['ALP'] > 125: abnormal_count += 1 if pd.notna(row.get('TBIL')) and row['TBIL'] > 20: abnormal_count += 1 if abnormal_count == 0: return '姝e父' elif abnormal_count == 1: return '杞诲害寮傚父' elif abnormal_count == 2: return '涓<>害寮傚父' else: return '閲嶅害寮傚父' df['liver_function_grade'] = df.apply(classify_liver_function, axis=1)
鐜板湪锛岃<EFBFBD>鍑嗗<EFBFBD>濂芥帴鏀剁敤鎴风殑鎸囦护銆傝<EFBFBD>浣忥細浠g爜瑕佸畨鍏ㄣ€佸彲闈犮€佹槗鎳傦紝鑳藉<EFBFBD>鐞嗕粠鍩虹<EFBFBD>鍒伴珮绾х殑澶嶆潅鍖荤枟鍦烘櫙銆? `; }
- [ ] 闆嗘垚LLMFactory锛堚渽 澶嶇敤骞冲彴閫氱敤鑳藉姏灞傦級
```typescript
// backend/src/modules/dc/tool-c/services/AICodeService.ts
import { LLMFactory } from '@/common/llm'; // 鉁?澶嶇敤骞冲彴LLM鑳藉姏
import { logger } from '@/common/logging'; // 鉁?澶嶇敤鏃ュ織
export class AICodeService {
/**
* 鐢熸垚Pandas浠g爜锛堚渽 澶嶇敤LLMFactory锛?
*/
async generateCode(prompt: string, dataContext: DataContext): Promise<string> {
logger.info('Generating Pandas code', { prompt, dataContext });
// 鉁?澶嶇敤骞冲彴LLM鏈嶅姟
const llm = LLMFactory.getLLM('deepseek-v3');
const systemPrompt = buildSystemPrompt(dataContext);
const response = await llm.chat([
{ role: 'system', content: systemPrompt },
{ role: 'user', content: prompt }
]);
// 鎻愬彇绾<E5BD87>唬鐮侊紙鍘婚櫎Markdown鏍煎紡锛?
const code = this.extractCode(response.content);
logger.info('Code generated successfully', { codeLength: code.length });
return code;
}
/**
* AI鑷<49>垜淇<E59E9C><E6B787>锛堝け璐ュ悗閲嶈瘯1娆★級
*/
async fixCode(originalCode: string, errorMsg: string, dataContext: DataContext): Promise<string> {
logger.warn('Code execution failed, attempting self-repair', { errorMsg });
const llm = LLMFactory.getLLM('deepseek-v3');
const fixPrompt = `浠ヤ笅浠g爜鎵ц<E98EB5>澶辫触锛岃<E9949B>淇<EFBFBD><E6B787>锛?
閿欒<E996BF>淇℃伅锛?
${errorMsg}
鍘熷<E98D98>浠g爜锛?
${originalCode}
鏁版嵁缁撴瀯锛?
${JSON.stringify(dataContext)}
璇风敓鎴愪慨澶嶅悗鐨勪唬鐮侊紙涓嶈<E6B693>鏈塎arkdown鏍煎紡锛夛細`;
const response = await llm.chat([{ role: 'user', content: fixPrompt }]);
return this.extractCode(response.content);
}
private extractCode(text: string): string {
// 鍘婚櫎```python```鎴朻``鏍囪<E98F8D>
const match = text.match(/```(?:python)?\n([\s\S]*?)\n```/);
return match ? match[1] : text;
}
}
*娴嬭瘯鐢ㄤ緥锛?
- 杈撳叆"骞撮緞鍒嗙粍"锛岀敓鎴愭<E98EB4>纭<EFBFBD>唬鐮?
- 杈撳叆"鍒犻櫎绌鸿<E7BB8C>"锛岀敓鎴愭<E98EB4>纭<EFBFBD>唬鐮?
- 妫€鏌ヤ唬鐮佷腑鏄<EFBFBD>惁鍖呭惈鍗遍櫓璇<EFBFBD>彞
*楠屾敹鏍囧噯锛?
- 鉁?AI鑳界敓鎴愬彲鎵ц<E98EB5>鐨凱andas浠g爜
- 鉁?浠g爜绗﹀悎瑙勮寖锛堟棤print銆佹棤import锛?
璐熻矗浜猴細 Node.js鍚庣<E98D9A>
Week 2锛氭牳蹇冨姛鑳藉紑鍙戯紙5澶╋級
Day 6-7锛欰I浠g爜鐢熸垚 + AST妫€鏌?
*Day 6浠诲姟锛?
- 瀹炵幇AST闈欐€佹<EFBFBD>鏌?
# python-service/code_validator.py import ast DANGEROUS_IMPORTS = {'os', 'sys', 'subprocess', 'requests', 'urllib'} DANGEROUS_BUILTINS = {'eval', 'exec', 'compile', 'open', '__import__'} def validate_code_safety(code: str) -> Tuple[bool, str]: try: tree = ast.parse(code) for node in ast.walk(tree): # 妫€鏌<E282AC>mport if isinstance(node, ast.Import): for alias in node.names: if alias.name in DANGEROUS_IMPORTS: return False, f"绂佹<E7BB82>瀵煎叆锛歿alias.name}" # 妫€鏌ュ嚱鏁拌皟鐢? if isinstance(node, ast.Call): if isinstance(node.func, ast.Name): if node.func.id in DANGEROUS_BUILTINS: return False, f"绂佹<E7BB82>浣跨敤锛歿node.func.id}" return True, "楠岃瘉閫氳繃" except SyntaxError as e: return False, f"璇<>硶閿欒<E996BF>锛歿str(e)}"
*Day 7浠诲姟锛?
- 瀹炵幇AI浠g爜鐢熸垚API
// Node.js fastify.post('/api/v1/dc/tool-c/ai/generate', async (req, reply) => { const { sessionId, prompt } = req.body; // 1. 鑾峰彇鏁版嵁涓婁笅鏂? const context = await pythonService.getDataContext(sessionId); // 2. 璋冪敤AI鐢熸垚浠g爜 const code = await aiService.generateCode(prompt, context); return { success: true, code, summary: `灏嗘墽琛屼互涓嬫搷浣滐細${extractSummary(code)}` }; });
*娴嬭瘯鍦烘櫙锛?5涓<35>湡瀹炲尰鐤楁暟鎹<E69A9F>竻娲楀満鏅<E6BA80>級锛?
馃煝 鍩虹<E98DA9>鍦烘櫙锛?涓<>級- 鍗曟<E98D97>楠ゆ搷浣滐細
- "鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁? - 绠€鍗曟潯浠跺垽鏂?
- "鍒犻櫎鎵€鏈夋偅鑰匢D涓虹┖鐨勮<E990A8>" - 鏁版嵁瀹屾暣鎬ф竻娲?
- "鎶婃€у埆杞<E59F86>负鏁板瓧锛岀敺1濂?" - 鍒嗙被鍙橀噺缂栫爜
- "璁$畻BMI = 浣撻噸 / (韬<>珮/100)^2" - 绠€鍗曞叕寮忚<E5AFAE>绠?
- "鍒犻櫎缂哄け鐜囪秴杩?0%鐨勫垪" - 鍒楃骇鏁版嵁璐ㄩ噺鎺у埗
*馃煛 涓<>瓑鍦烘櫙锛?涓<>級- 澶氭<E6BEB6>楠ゆ垨璺ㄥ垪閫昏緫锛? 6. [ ] "鎶婅瘖鏂<E79896>棩鏈熷拰鍑洪櫌鏃ユ湡璁$畻澶╂暟宸<E69A9F>紝濡傛灉鍑洪櫌鏃ユ湡鏃╀簬璇婃柇鏃ユ湡鍒欐爣璁颁负寮傚父" - 閫昏緫楠岃瘉 7. [ ] "鏍规嵁鐧界粏鑳炪€佷腑鎬х矑缁嗚優銆佹穻宸寸粏鑳炰笁涓<E7AC81>寚鏍囷紝璁$畻NLR锛堜腑鎬х矑缁嗚優/娣嬪反缁嗚優锛夛紝骞舵寜2.5鍒嗕负楂樹綆涓ょ粍" - 澶氭<E6BEB6>楠よ<E6A5A0>绠? 8. [ ] "浠庣梾鐞嗘姤鍛婂垪涓<E59EAA>彁鍙朤NM鍒嗘湡锛岀敓鎴愭柊鍒楋紝濡傛灉娌℃湁鎻愬彇鍒板垯鏍囪<E98F8D>涓?鏈<>垎鏈?" - 鏂囨湰鎻愬彇锛堝彲鐢ㄦ<E990A2>鍒欙級 9. [ ] "鎶婅<E98EB6>鍘嬪垪涓<E59EAA>殑'120/80'鏍煎紡鎷嗗垎鎴愭敹缂╁帇鍜岃垝寮犲帇涓ゅ垪锛屽苟鍒ゆ柇鏄<E69F87>惁楂樿<E6A582>鍘嬶紙鏀剁缉鍘?140 or 鑸掑紶鍘?90锛? - 瀛楃<E7809B>涓插<E6B693>鐞?閫昏緫鍒ゆ柇 10. [ ] "鍒犻櫎閲嶅<E996B2>鐨勬偅鑰匢D锛屼繚鐣欐渶鏂扮殑涓€鏉¤<E98F89>褰曪紙鏍规嵁灏辫瘖鏃ユ湡锛? - 鍘婚噸+鎺掑簭
馃敶 楂樼骇鍦烘櫙锛?涓<>級- 澶嶆潅鍒嗙粍銆佹椂闂村簭鍒椼€佸尰瀛﹁<E7809B>鍒欙細 11. [ ] "瀵逛簬姣忎釜鎮h€咃紝鎵惧嚭绗<E59AAD>竴娆″寲鐤楁棩鏈熷拰鏈€鍚庝竴娆″寲鐤楁棩鏈燂紝璁$畻鍖栫枟鎸佺画鏃堕棿" - 鍒嗙粍鑱氬悎 12. [ ] "鐢熸垚鐢熷瓨鐘舵€佸彉閲忥細濡傛灉姝讳骸鏃ユ湡瀛樺湪鍒欎负1锛屽惁鍒欎负0锛涚敓鎴愮敓瀛樻椂闂达細濡傛灉姝讳骸鍒欎负锛堟<E9949B>浜℃棩鏈?璇婃柇鏃ユ湡锛夛紝鍚﹀垯涓猴紙闅忚<E99785>鎴<EFBFBD><E98EB4>鏃ユ湡-璇婃柇鏃ユ湡锛? - 澶嶆潅鏉′欢閫昏緫 13. [ ] "鏍规嵁澶氫釜瀹為獙瀹ゆ寚鏍囷紙ALT銆丄ST銆丄LP銆乀BIL锛夊垽鏂<E59EBD>倽鍔熻兘鍒嗙骇锛堟<E9949B>甯搞€佽交搴﹀紓甯搞€佷腑搴﹀紓甯搞€侀噸搴﹀紓甯革級" - 鍖诲<E98D96>瑙勫垯寮曟搸 14. [ ] "鎸夋偅鑰匢D鍒嗙粍锛屽<E9949B>姣忎釜鎮h€呯殑澶氭<E6BEB6>闅忚<E99785>璁板綍锛岃<E9949B>绠楃浉閭讳袱娆′箣闂寸殑鎸囨爣鍙樺寲鐜囷紙濡傝偪鐦ゅぇ灏忓彉鍖栫巼锛? - 鏃堕棿搴忓垪鍒嗘瀽 15. [ ] "鏍规嵁鍏ラ櫌鏃堕棿锛岃<E9949B>绠楁偅鑰呯殑瀛h妭鍙橀噺锛堟槬澶忕<E6BEB6>鍐<EFBFBD>級锛岀劧鍚庣粺璁′笉鍚屽<E98D9A>鑺傜殑鍙戠梾浜烘暟" - 鏃堕棿鐗瑰緛鎻愬彇+缁熻<E7BC81>鍒嗘瀽
*楠屾敹鏍囧噯锛堝垎灞傝<EFBFBD>姹傦級锛?
- 鉁?**鍩虹<E98DA9>鍦烘櫙鎴愬姛鐜?> 90%**锛?/5鎴?/5鎴愬姛锛?
- 鉁?**涓<>瓑鍦烘櫙鎴愬姛鐜?> 80%**锛?/5鎴愬姛锛?
- 鉁?**楂樼骇鍦烘櫙鎴愬姛鐜?> 60%**锛?/5鎴愬姛锛?
- 鉁?**鎬讳綋鎴愬姛鐜?> 80%**锛?2/15鍦烘櫙鎴愬姛锛?
- 鉁?AST鑳芥嫤鎴猔import os`绛夊嵄闄╀唬鐮?
- 鉂?濡傛灉鎬讳綋鎴愬姛鐜?< 60%锛?/15澶辫触锛夛紝MVP澶辫触锛岄渶瑕丳ivot鍒版ā鏉垮簱妯″紡
璐熻矗浜猴細 Node.js鍚庣<E98D9A> + Python寮€鍙?
Day 8锛氫唬鐮佹墽琛?+ 琛ㄦ牸鍒锋柊
*浠诲姟娓呭崟锛?
- 瀹炵幇浠g爜鎵ц<EFBFBD>API
# Python @app.post("/api/python/execute") async def execute_code(request: ExecuteRequest): # 1. 鑾峰彇Session df = session_manager.get(request.sessionId) # 2. AST妫€鏌? is_safe, error_msg = validate_code_safety(request.code) if not is_safe: return {"success": False, "error": error_msg} # 3. 鎵ц<E98EB5>浠g爜 try: exec(request.code, {'df': df, 'pd': pd, 'np': np}) # 4. 杩斿洖棰勮<E6A3B0>鏁版嵁 preview = df.head(100).to_dict('records') return { "success": True, "preview": preview, "stats": { "totalRows": len(df), "totalCols": len(df.columns) } } except Exception as e: return { "success": False, "error": str(e), "traceback": traceback.format_exc() } - 鍓嶇<EFBFBD>鎵ц<EFBFBD>娴佺▼
async function executeAICode(code: string) { // 1. 灞曠ず棰勬搷浣滃崱鐗? const confirmed = await showActionCard(code); if (!confirmed) return; // 2. 閿佸畾琛ㄦ牸 setIsLocked(true); try { // 3. 鎵ц<E98EB5>浠g爜 const response = await api.post('/api/v1/dc/tool-c/ai/execute', { sessionId, code }); if (response.data.success) { // 4. 鍒锋柊琛ㄦ牸 setData(response.data.preview); message.success('鎵ц<E98EB5>鎴愬姛锛?); } else { message.error(`鎵ц<E98EB5>澶辫触锛?{response.data.error}`); } } finally { // 5. 瑙i攣琛ㄦ牸 setIsLocked(false); } }
*娴嬭瘯鐢ㄤ緥锛?
- 鎵ц<EFBFBD>鎴愬姛锛岃〃鏍兼<EFBFBD>纭<EFBFBD>埛鏂?
- 鎵ц<EFBFBD>澶辫触锛屾樉绀洪敊璇<EFBFBD>俊鎭?
- 鎵ц<EFBFBD>鏈熼棿锛岃〃鏍煎<EFBFBD>浜庨攣瀹氱姸鎬?
*楠屾敹鏍囧噯锛?
- 鉁?浠g爜鑳芥<E991B3>纭<EFBFBD>慨鏀笵ataFrame
- 鉁?鍓嶇<E98D93>鑳藉疄鏃剁湅鍒板彉鍖?
璐熻矗浜猴細 Python寮€鍙?+ 鍓嶇<E98D93>
Day 9锛歎I閿佸畾 + 棰勬搷浣滃崱鐗?
*浠诲姟娓呭崟锛?
- 瀹炵幇AI瀵硅瘽UI
function AIChatPanel({ sessionId }: Props) { const [messages, setMessages] = useState<Message[]>([]); const [input, setInput] = useState(''); const [isProcessing, setIsProcessing] = useState(false); const handleSend = async () => { if (!input.trim()) return; // 1. 娣诲姞鐢ㄦ埛娑堟伅 setMessages(prev => [...prev, { role: 'user', content: input }]); setIsProcessing(true); // 2. 璋冪敤AI鐢熸垚浠g爜 const response = await api.post('/api/v1/dc/tool-c/ai/generate', { sessionId, prompt: input }); // 3. 娣诲姞AI娑堟伅锛堝寘鍚<E5AF98>唬鐮侊級 setMessages(prev => [...prev, { role: 'assistant', content: response.data.summary, code: response.data.code }]); setIsProcessing(false); setInput(''); }; return ( <div className="flex flex-col h-full"> {/* 娑堟伅鍒楄〃 */} <div className="flex-1 overflow-y-auto p-4"> {messages.map((msg, idx) => ( <MessageBubble key={idx} message={msg} /> ))} </div> {/* 杈撳叆妗?*/} <div className="p-4 border-t"> <Input.TextArea value={input} onChange={e => setInput(e.target.value)} placeholder="杈撳叆鎸囦护锛屼緥濡傦細鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁? disabled={isProcessing} /> <Button onClick={handleSend} disabled={isProcessing}> 鍙戦€? </Button> </div> </div> ); } - 瀹炵幇棰勬搷浣滃崱鐗?
function ActionCard({ code, onConfirm, onCancel }: Props) { return ( <Card className="mt-2 bg-slate-900 text-white"> <div className="mb-2 text-xs text-slate-400"> AI鐢熸垚鐨勪唬鐮?- 璇风‘璁ゅ悗鎵ц<EFBFBD> </div> <pre className="text-sm font-mono text-blue-300"> {code} </pre> <div className="mt-3 flex gap-2"> <Button type="primary" onClick={onConfirm}> 杩愯<EFBFBD>浠g爜 </Button> <Button onClick={onCancel}> 鍙栨秷 </Button> </div> </Card> ); } - 瀹炵幇UI閿佸畾
<AgGridReact rowData={data} suppressClickEdit={isLocked} readOnlyEdit={isLocked} /> {isLocked && ( <div className="absolute inset-0 bg-black/20 flex items-center justify-center"> <Spin tip="AI姝e湪澶勭悊涓<E6828A>紝璇风◢鍊?.." /> </div> )}
*楠屾敹鏍囧噯锛?
- 鉁?鐢ㄦ埛鑳藉彂閫佹秷鎭?
- 鉁?AI杩斿洖浠g爜鏃跺睍绀洪<E7BB80>鎿嶄綔鍗$墖
- 鉁?鎵ц<E98EB5>鏈熼棿琛ㄦ牸閿佸畾
璐熻矗浜猴細 鍓嶇<E98D93>
Day 10锛氬<E9949B>鍑?+ 绔<>埌绔<E59F8C>祴璇?
*浠诲姟娓呭崟锛?
- 瀹炵幇瀵煎嚭API
@app.get("/api/python/export/{session_id}") async def export_excel(session_id: str): df = session_manager.get(session_id) # 鐢熸垚Excel output = io.BytesIO() df.to_excel(output, index=False, engine='openpyxl') output.seek(0) return StreamingResponse( output, media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', headers={ 'Content-Disposition': f'attachment; filename=cleaned_data_{session_id}.xlsx' } ) - 鍓嶇<EFBFBD>瀵煎嚭鎸夐挳
const handleExport = async () => { const response = await api.get(`/api/v1/dc/tool-c/session/export/${sessionId}`, { responseType: 'blob' }); const url = window.URL.createObjectURL(response.data); const a = document.createElement('a'); a.href = url; a.download = 'cleaned_data.xlsx'; a.click(); }; - *绔<EFBFBD>埌绔<EFBFBD>祴璇曪紙瀹屾暣娴佺▼锛?
1. 涓婁紶 test_data.xlsx (5000琛?脳 20鍒? 2. AI鎸囦护锛?鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁? 3. 纭<><E7BAAD> 鈫?鎵ц<E98EB5> 鈫?琛ㄦ牸鍒锋柊锛堥獙璇佹柊澧炲垪锛? 4. AI鎸囦护锛?鍒犻櫎鎮h€匢D涓虹┖鐨勮<E990A8>" 5. 纭<><E7BAAD> 鈫?鎵ц<E98EB5> 鈫?琛ㄦ牸鍒锋柊锛堥獙璇佽<E79287>鏁板噺灏戯級 6. 鐐瑰嚮"瀵煎嚭" 鈫?涓嬭浇鏂囦欢 7. 鎵撳紑涓嬭浇鐨勬枃浠讹紝楠岃瘉鏁版嵁姝g‘
*楠屾敹鏍囧噯锛?
- 鉁?鏁翠釜娴佺▼ < 2鍒嗛挓
- 鉁?瀵煎嚭鐨凟xcel鏁版嵁姝g‘
- 鉁?AI浠g爜鎵ц<E98EB5>鎴愬姛
璐熻矗浜猴細 鍏ㄥ憳
Week 3锛氫紭鍖栦笌娴嬭瘯锛?澶╋級
Day 11-12锛氶敊璇<E6958A><E79287>鐞?+ AI鑷<49>垜淇<E59E9C><E6B787>
*浠诲姟娓呭崟锛?
- 瀹炵幇AI鑷<EFBFBD>垜淇<EFBFBD><EFBFBD>
async function executeWithRetry(code: string): Promise<ExecuteResult> { // 绗<>竴娆℃墽琛? let result = await pythonService.execute(sessionId, code); if (!result.success) { // 澶辫触锛岃<E9949B>AI淇<49><E6B787> const fixedCode = await aiService.fixCode(code, result.error); // 閲嶈瘯1娆? result = await pythonService.execute(sessionId, fixedCode); if (!result.success) { // 褰诲簳澶辫触 return { success: false, error: '浠g爜鎵ц<E98EB5>澶辫触锛岃<E9949B>灏濊瘯鏇磋<E98F87>缁嗗湴鎻忚堪鎮ㄧ殑闇€姹?, originalError: result.error }; } } return result; } - 浼樺寲閿欒<EFBFBD>鎻愮ず
function showErrorDetail(error: string) { const errorMap = { "KeyError: 'age'": "鍒楀悕'age'涓嶅瓨鍦<E793A8>紝璇锋<E79287>鏌ュ垪鍚嶆槸鍚︽<E98D9A>纭?, "ValueError": "鏁版嵁绫诲瀷涓嶅尮閰嶏紝璇锋<EFBFBD>鏌ユ暟鎹<EFBFBD>牸寮?, "MemoryError": "鏁版嵁閲忚繃澶э紝璇峰噺灏戞暟鎹<E69A9F><E98EB9>鏁? }; const friendlyMsg = errorMap[error] || error; Modal.error({ title: '鎵ц<E98EB5>澶辫触', content: friendlyMsg }); }
*娴嬭瘯鍦烘櫙锛堣竟鐣屾儏鍐碉級锛?
- 鍒楀悕涓嶅瓨鍦<EFBFBD>細
df['nonexistent'] - 璇<EFBFBD>硶閿欒<EFBFBD>锛歚df[df['age'] > 60 and df['age'] < 80]`
- 鏁版嵁绫诲瀷閿欒<EFBFBD>锛歚df['age'] + '瀛楃<E7809B>涓?`
- 鍐呭瓨婧㈠嚭锛氬<EFBFBD>鐞嗚秴澶ф暟鎹?
*楠屾敹鏍囧噯锛?
- 鉁?甯歌<E794AF>閿欒<E996BF>鑳借嚜鎴戜慨澶?
- 鉁?鏃犳硶淇<E7A1B6><E6B787>鏃舵湁鍙嬪ソ鎻愮ず
璐熻矗浜猴細 Node.js鍚庣<E98D9A>
Day 13锛氬揩鎹锋ā鏉?+ 缂栫爜妫€娴?
*浠诲姟娓呭崟锛?
- 瀹炵幇蹇<EFBFBD>嵎妯℃澘
const QUICK_TEMPLATES = { '骞撮緞鍒嗙粍': { label: '骞撮緞鍒嗙粍锛?0宀佸垎鐣岋級', code: `df['age_group'] = pd.cut(df['age'], bins=[0,60,150], labels=['闈炶€佸勾','鑰佸勾'])` }, '鍒犻櫎绌鸿<E7BB8C>': { label: '鍒犻櫎绌鸿<E7BB8C>', code: `df.dropna(how='all', inplace=True)` }, '鎬у埆缂栫爜': { label: '鎬у埆缂栫爜锛堢敺1濂?锛?, code: `df['gender_code'] = df['gender'].map({'鐢?:1, '濂?:0})` } }; function QuickActions() { return ( <div className="p-4 border-t"> <div className="text-xs text-slate-500 mb-2">蹇<>嵎鎿嶄綔</div> {Object.entries(QUICK_TEMPLATES).map(([key, template]) => ( <Button key={key} size="small" onClick={() => executeTemplate(template.code)} > {template.label} </Button> ))} </div> ); } - 瀹炵幇缂栫爜妫€娴?
import chardet def detect_encoding(file_bytes: bytes) -> str: result = chardet.detect(file_bytes) encoding = result['encoding'] confidence = result['confidence'] if confidence < 0.8: raise ValueError(f"鏃犳硶纭<E7A1B6>畾鏂囦欢缂栫爜锛堢疆淇″害{confidence:.0%}锛?) return encoding @app.post("/api/python/init") async def init_session(file: UploadFile): content = await file.read() # 妫€娴嬬紪鐮? encoding = detect_encoding(content) if encoding.lower() not in ['utf-8', 'utf-8-sig']: return { "success": False, "error": f"鏂囦欢缂栫爜涓簕encoding}锛岃<EFBFBD>杞<EFBFBD>崲涓篣TF-8鍚庨噸鏂颁笂浼?, "suggestion": "鍦‥xcel涓<6C>彟瀛樹负CSV UTF-8鏍煎紡" } # 姝e父鍔犺浇 # ...
*楠屾敹鏍囧噯锛?
- 鉁?蹇<>嵎妯℃澘涓€閿<E282AC>墽琛?
- 鉁?GBK鏂囦欢琚<E6ACA2>弸濂芥嫤鎴?
璐熻矗浜猴細 鍓嶇<E98D93> + Python寮€鍙?
Day 14锛氭€ц兘娴嬭瘯 + 鍘嬪姏娴嬭瘯
*娴嬭瘯鍦烘櫙锛?
- 鎬ц兘娴嬭瘯
娴嬭瘯鏁版嵁锛?000琛?脳 20鍒楋紙绾?MB锛? 鍦烘櫙1锛氫笂浼犳枃浠? - 鐩<>爣锛? 5绉? - 瀹炴祴锛歘___绉? 鍦烘櫙2锛欰I鐢熸垚浠g爜 - 鐩<>爣锛? 5绉? - 瀹炴祴锛歘___绉? 鍦烘櫙3锛氫唬鐮佹墽琛?鍒锋柊 - 鐩<>爣锛? 3绉? - 瀹炴祴锛歘___绉? 鍦烘櫙4锛氬<E9949B>鍑篍xcel - 鐩<>爣锛? 3绉? - 瀹炴祴锛歘___绉? 鎬昏<E98EAC>锛? 16绉? - 鍘嬪姏娴嬭瘯
鍦烘櫙1锛氬苟鍙戠敤鎴? - 5涓<35>敤鎴峰悓鏃朵笂浼犳枃浠? - 楠岃瘉锛歋ession闅旂<E99785>锛屼簰涓嶅奖鍝? 鍦烘櫙2锛氬ぇ鏁版嵁閲? - 涓婁紶50000琛?脳 50鍒楋紙绾?0MB锛? - 楠岃瘉锛氫笉宕╂簝锛屽搷搴旀椂闂村彲鎺ュ彈 鍦烘櫙3锛氳繛缁<E7B99B>搷浣? - 杩炵画鎵ц<E98EB5>10娆<30>I鎸囦护 - 楠岃瘉锛氬唴瀛樹笉娉勬紡
鎬ц兘浼樺寲锛堝<EFBFBD>鏋滀笉杈炬爣锛夛細
- 鍓嶇<EFBFBD>锛欰G Grid铏氭嫙婊氬姩閰嶇疆
- 鍚庣<EFBFBD>锛欴ataFrame鎿嶄綔鏀逛负鎯版€ц<EFBFBD>绠?
- Python锛氫娇鐢≒olars鏇夸唬Pandas锛堝<EFBFBD>鏋滈渶瑕侊級
*楠屾敹鏍囧噯锛?
- 鉁?鍗曟<E98D97>鎿嶄綔 < 16绉?
- 鉁?5涓<35>苟鍙戠敤鎴锋<E98EB4>甯稿伐浣?
- 鉁?鏃犲唴瀛樻硠婕?
璐熻矗浜猴細 鍏ㄥ憳
Day 15锛氭枃妗?+ 婕旂ず鍑嗗<E98D91>
*浠诲姟娓呭崟锛?
- 缂栧啓鐢ㄦ埛鏂囨。
# 宸ュ叿C浣跨敤鎸囧崡 ## 蹇<>€熷紑濮? 1. 鐐瑰嚮"涓婁紶鏂囦欢"锛岄€夋嫨Excel锛堥檺10MB锛? 2. 绛夊緟3-5绉掞紝琛ㄦ牸鍔犺浇瀹屾垚 3. 鍦ㄥ彸渚<E5BDB8>I鍔╂墜杈撳叆鎸囦护锛屼緥濡傦細"鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁? 4. 鐐瑰嚮"杩愯<E69DA9>浠g爜"纭<><E7BAAD> 5. 鏌ョ湅琛ㄦ牸鑷<E789B8>姩鍒锋柊 6. 瀹屾垚鎵€鏈夋搷浣滃悗锛岀偣鍑?瀵煎嚭"涓嬭浇缁撴灉 ## 甯歌<E794AF>闂<EFBFBD><E99782> Q: 鏂囦欢涓婁紶澶辫触锛屾彁绀烘枃浠惰繃澶э紵 A: 璇峰皢Excel鏂囦欢鍘嬬缉鍒?0MB浠ュ唴锛屾垨鍒犻櫎涓嶉渶瑕佺殑鍒椼€? Q: 鍒楀悕鏄剧ず涔辩爜锛? A: 璇峰湪Excel涓<6C>彟瀛樹负"CSV UTF-8"鏍煎紡鍚庨噸鏂颁笂浼犮€? - 鍑嗗<EFBFBD>婕旂ず鏁版嵁
鍒涘缓 demo_data.xlsx锛? - 100琛屾偅鑰呮暟鎹? - 鍖呭惈锛歱atient_id, name, age, gender, admission_date, bmi - 鏁呮剰鍒堕€犱竴浜涢棶棰橈細绌哄€笺€佸紓甯稿€笺€侀渶瑕佹竻娲楃殑鏁版嵁 - 鍑嗗<EFBFBD>婕旂ず鑴氭湰
婕旂ず娴佺▼锛?鍒嗛挓锛夛細 1. 涓婁紶demo_data.xlsx 2. AI鎸囦护锛?鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁? 3. AI鎸囦护锛?鍒犻櫎鎮h€匢D涓虹┖鐨勮<E990A8>" 4. AI鎸囦护锛?鎶婃€у埆杞<E59F86>负鏁板瓧锛岀敺1濂?" 5. 瀵煎嚭缁撴灉 6. 灞曠ず瀵煎嚭鐨凟xcel鏂囦欢
*楠屾敹鏍囧噯锛?
- 鉁?鏂囨。娓呮櫚鏄撴噦
- 鉁?婕旂ず娴佺晠鏃犲崱椤?
- 鉁?婕旂ず鏁版嵁鑳戒綋鐜版牳蹇冨姛鑳?
璐熻矗浜猴細 鍏ㄥ憳
浜斻€侀<EFBFBD>闄╁簲瀵圭瓥鐣?
5.1 椋庨櫓娓呭崟涓庡簲瀵?
| 椋庨櫓 | 姒傜巼 | 褰卞搷 | 搴斿<EFBFBD>绛栫暐 | 闄嶇骇鏂规<EFBFBD> |
|---|---|---|---|---|
| *AI浠g爜璐ㄩ噺浣庯紙鎴愬姛鐜?60%锛? | 涓? | 鑷村懡 | 1. 浼樺寲Prompt宸ョ▼ 2. 澧炲姞Few-shot绀轰緥 3. 瀹炵幇鑷<E5B987>垜淇<E59E9C><E6B787> |
Pivot锛氭敼鐢ㄤ唬鐮佹ā鏉垮簱 |
| Apache Arrow闆嗘垚鍥伴毦 | 楂? | 楂? | 1. MVP涓嶇敤Arrow 2. 鐩存帴鐢↗SON |
宸查檷绾э細MVP鐢↗SON |
| *Redis鍐呭瓨鎴愭湰楂? | 涓? | 涓? | 1. MVP鐢ㄨ繘绋嬪唴瀛?br>2. 婵€杩涚殑Session杩囨湡 | 宸查檷绾э細鐢∕ap缂撳瓨 |
| Python鍐呭瓨娉勬紡 | 涓? | 楂? | 1. 涓嶅仛鍘嗗彶蹇<E5BDB6>収 2. 瀹氭湡閲嶅惎杩涚▼ |
SAE鑷<EFBFBD>姩閲嶅惎 |
| 涓<EFBFBD>枃Excel涔辩爜 | 楂? | 涓? | 1. chardet鑷<74>姩妫€娴?br>2. 鍙嬪ソ鎶ラ敊鎻愮ず | 鏂囨。璇存槑杞琔TF-8 |
| SAE鍐峰惎鍔ㄦ參 | 楂? | 涓? | 1. 鏈€灏忓疄渚嬫暟=1 2. 寮傛<E5AFAE>鍒濆<E98D92>鍖? |
Loading浼樺寲 |
| *鍓嶇<EFBFBD>AG Grid鎬ц兘宸? | 浣? | 涓? | 1. 鍙<>睍绀?00琛?br>2. 铏氭嫙婊氬姩 | *宸蹭紭鍖? |
5.2 蹇<>€熷け璐ヨЕ鍙戝櫒
*绔嬪嵆鍋滄<EFBFBD>寮€鍙戠殑鏉′欢锛?
-
Day 7缁撴潫锛孉I浠g爜鎴愬姛鐜?< 60%
- 鍐崇瓥锛氭斁寮傾I Code Interpreter璺<72>嚎
- Pivot锛氭敼涓?浠g爜妯℃澘搴?+ 鍙傛暟鍖栭厤缃?
-
*Day 10缁撴潫锛岀<E9949B>鍒扮<E98D92>鏃堕棿 > 30绉?
- 鍐崇瓥锛氭€ц兘鏃犳硶鎺ュ彈
- Pivot锛氭敼涓烘壒澶勭悊妯″紡锛堜笂浼?鈫?鍚庡彴澶勭悊 鈫?涓嬭浇锛?
-
*Day 14缁撴潫锛?涓<>敤鎴锋祴璇曪紝閮芥棤娉曠嫭绔嬪畬鎴愪换鍔?
- 鍐崇瓥锛氫氦浜掕<EFBFBD>璁″け璐?
- Pivot锛氶噸鏂拌<EFBFBD>璁<EFBFBD>I锛屽<EFBFBD>鍔犳柊鎵嬪紩瀵?
鍏<EFBFBD>€侀獙鏀舵爣鍑?
6.1 鍔熻兘楠屾敹娓呭崟
| 缂栧彿 | 楠屾敹椤? | 楠屾敹鏍囧噯 | 楠屾敹鏂瑰紡 |
|---|---|---|---|
| F-001 | 鏂囦欢涓婁紶 | 鑳戒笂浼?0MB浠ュ唴鐨凟xcel | 鎵嬪姩娴嬭瘯 |
| F-002 | 缂栫爜妫€娴? | GBK鏂囦欢琚<EFBFBD>弸濂芥嫤鎴? | 鎵嬪姩娴嬭瘯 |
| F-003 | 琛ㄦ牸灞曠ず | 100琛屾暟鎹<EFBFBD><EFBFBD>纭<EFBFBD>樉绀猴紝涓<EFBFBD>枃鏃犱贡鐮? | 鎵嬪姩娴嬭瘯 |
| F-004 | AI瀵硅瘽 | 鑳藉彂閫佹秷鎭<EFBFBD>紝鎺ユ敹鍥炲<EFBFBD> | 鎵嬪姩娴嬭瘯 |
| F-005 | 浠g爜鐢熸垚 | *10涓<EFBFBD>満鏅<EFBFBD>紝8涓<EFBFBD>垚鍔燂紙80%锛? | 鑷<EFBFBD>姩鍖栨祴璇? |
| F-006 | AST妫€鏌? | 鎷︽埅import os绛夊嵄闄╀唬鐮? |
鍗曞厓娴嬭瘯 |
| F-007 | 浠g爜鎵ц<EFBFBD> | 鑳芥<EFBFBD>纭<EFBFBD>慨鏀笵ataFrame | 闆嗘垚娴嬭瘯 |
| F-008 | 琛ㄦ牸鍒锋柊 | 鎵ц<EFBFBD>鍚庤嚜鍔ㄦ洿鏂? | 鎵嬪姩娴嬭瘯 |
| F-009 | UI閿佸畾 | AI澶勭悊鏃惰〃鏍煎彧璇?閬<>僵 | 鎵嬪姩娴嬭瘯 |
| F-010 | 瀵煎嚭Excel | 涓嬭浇鐨勬枃浠舵暟鎹<EFBFBD><EFBFBD>纭? | 鎵嬪姩娴嬭瘯 |
6.2 鎬ц兘楠屾敹鏍囧噯
| 鎸囨爣 | 鐩<EFBFBD>爣鍊? | 楠屾敹鏂瑰紡 |
|---|---|---|
| 鏂囦欢涓婁紶鍒拌〃鏍兼樉绀? | < 5绉? | 鎬ц兘娴嬭瘯 |
| AI鐢熸垚浠g爜 | < 5绉? | 鎬ц兘娴嬭瘯 |
| 浠g爜鎵ц<EFBFBD>+鍒锋柊 | < 3绉? | 鎬ц兘娴嬭瘯 |
| 瀵煎嚭Excel | < 3绉? | 鎬ц兘娴嬭瘯 |
| *绔<EFBFBD>埌绔<EFBFBD>€绘椂闂? | *< 16绉? | 鎬ц兘娴嬭瘯 |
| 骞跺彂鐢ㄦ埛鏁? | 鈮?5浜? | 鍘嬪姏娴嬭瘯 |
| 鍐呭瓨鍗犵敤 | < 2GB锛?鐢ㄦ埛锛? | 鍘嬪姏娴嬭瘯 |
6.3 瀹夊叏楠屾敹鏍囧噯
| 鎸囨爣 | 楠屾敹鏍囧噯 | 楠屾敹鏂瑰紡 |
|---|---|---|
| 浠g爜娌欑<EFBFBD> | 鎷︽埅鎵€鏈夊嵄闄╀唬鐮? | 娓楅€忔祴璇? |
| Session闅旂<EFBFBD> | 鐢ㄦ埛A鐪嬩笉鍒扮敤鎴稡鏁版嵁 | 骞跺彂娴嬭瘯 |
| Session杩囨湡 | 10鍒嗛挓鍚庤嚜鍔ㄦ竻鐞? | 鏃堕棿娴嬭瘯 |
涓冦€佸揩閫熷け璐ユ満鍒?
7.1 鍏抽敭妫€鏌ョ偣
Checkpoint 1 (Day 5缁撴潫)锛?
鈹溾攢 System Prompt鑳藉惁璁〢I鐞嗚В鏁版嵁锛?
鈹溾攢 AI鑳界敓鎴怭andas浠g爜鍚楋紵
鈹斺攢 鍐崇瓥锛氱户缁?or 璋冩暣Prompt绛栫暐
Checkpoint 2 (Day 7缁撴潫)锛?
鈹溾攢 AI浠g爜鎴愬姛鐜?鈮?80%锛?
鈹溾攢 濡傛灉 < 60%锛氱珛鍗冲仠姝<E4BBA0>紝鏀圭敤妯℃澘搴?
鈹斺攢 濡傛灉 60-80%锛氱户缁<E688B7>紭鍖朠rompt
Checkpoint 3 (Day 10缁撴潫)锛?
鈹溾攢 绔<>埌绔<E59F8C>祦绋嬭兘璺戦€氾紵
鈹溾攢 鎬ц兘 < 16绉掞紵
鈹斺攢 鍐崇瓥锛氱户缁?or 鎬ц兘浼樺寲
Checkpoint 4 (Day 14缁撴潫)锛?
鈹溾攢 鐢ㄦ埛娴嬭瘯閫氳繃锛?
鈹溾攢 鏃犻噸澶<E599B8>ug锛?
鈹斺攢 鍐崇瓥锛氬彂甯?or 淇<><E6B787>Bug
7.2 Pivot鍐崇瓥鏍?
濡傛灉 AI浠g爜鎴愬姛鐜?< 60%锛?
鈹溾攢 Pivot 1锛氭敼鐢?浠g爜妯℃澘搴?+ 鍙傛暟鍖栭厤缃?
鈹? 鈹斺攢 鐢ㄦ埛閫夋嫨妯℃澘 鈫?濉<>啓鍙傛暟 鈫?鐢熸垚浠g爜
鈹?
鈹溾攢 Pivot 2锛欰I鍙樻垚"杈呭姪寤鸿<E5AFA4>"瑙掕壊
鈹? 鈹斺攢 鐢ㄦ埛鎵嬪姩鍐欎唬鐮侊紝AI鎻愪緵寤鸿<E5AFA4>
鈹?
鈹斺攢 Pivot 3锛氱畝鍖栦负"鎵瑰<E98EB5>鐞嗘ā寮?
鈹斺攢 涓婁紶 鈫?閫夋嫨棰勮<E6A3B0>鎿嶄綔 鈫?鍚庡彴澶勭悊 鈫?涓嬭浇
濡傛灉 鎬ц兘鏃犳硶鎺ュ彈锛? 30绉掞級锛?
鈹溾攢 鏂规<E98F82>1锛氬紩鍏<E7B4A9>pache Arrow
鈹溾攢 鏂规<E98F82>2锛氫娇鐢≒olars鏇夸唬Pandas
鈹斺攢 鏂规<E98F82>3锛氭敼涓烘壒澶勭悊+寮傛<E5AFAE>閫氱煡
濡傛灉 鐢ㄦ埛鏃犳硶鐙<E7A1B6>珛瀹屾垚浠诲姟锛?
鈹溾攢 鏂规<E98F82>1锛氬<E9949B>鍔犱氦浜掑紡鏂版墜寮曞<E5AFAE>
鈹溾攢 鏂规<E98F82>2锛氭彁渚涚ず渚嬫暟鎹<E69A9F>泦
鈹斺攢 鏂规<E98F82>3锛氱畝鍖朥I锛屽噺灏戦€夐」
鍏<EFBFBD>€侀檮褰?
8.1 娴嬭瘯鏁版嵁鍑嗗<E98D91>
鍒涘缓鏍囧噯娴嬭瘯鏁版嵁闆嗭細
# create_test_data.py
import pandas as pd
import numpy as np
# 鐢熸垚5000琛屾祴璇曟暟鎹?
data = {
'patient_id': [f'P{i:04d}' for i in range(1, 5001)],
'name': [f'鎮h€厈i}' for i in range(1, 5001)],
'age': np.random.randint(18, 90, 5000),
'gender': np.random.choice(['鐢?, '濂?], 5000),
'admission_date': pd.date_range('2023-01-01', periods=5000, freq='H'),
'weight': np.random.uniform(45, 95, 5000).round(1),
'height': np.random.uniform(150, 190, 5000).round(0),
'diagnosis': np.random.choice(['鑲虹檶', '绯栧翱鐥?, '楂樿<EFBFBD>鍘?], 5000)
}
df = pd.DataFrame(data)
# 鏁呮剰鍒堕€犻棶棰?
df.loc[np.random.choice(5000, 100, replace=False), 'age'] = None # 100涓<30>己澶?
df.loc[np.random.choice(5000, 10, replace=False), 'age'] = 150 # 10涓<30>紓甯稿€?
df.loc[np.random.choice(5000, 50, replace=False), 'patient_id'] = None # 50涓<30>┖ID
df.to_excel('test_data.xlsx', index=False)
8.2 10涓<30>吀鍨嬪満鏅<E6BA80>祴璇曠敤渚?
# test_ai_scenarios.py
test_cases = [
{
"id": "TC-001",
"prompt": "鎶婂勾榫勫ぇ浜?0鐨勬偅鑰呮爣璁颁负鑰佸勾缁?,
"expected_code": "df['age_group'] = df['age'].apply(lambda x: '鑰佸勾缁? if pd.notna(x) and x > 60 else '闈炶€佸勾缁?)",
"verify": lambda df: 'age_group' in df.columns
},
{
"id": "TC-002",
"prompt": "鍒犻櫎鎵€鏈夋偅鑰匢D涓虹┖鐨勮<E990A8>",
"expected_code": "df.dropna(subset=['patient_id'], inplace=True)",
"verify": lambda df: df['patient_id'].isnull().sum() == 0
},
# ... 鍏朵綑8涓<38>満鏅?
]
8.3 鐜<><E9909C>閰嶇疆娓呭崟
*Node.js渚濊禆锛?
{
"dependencies": {
"fastify": "^4.0.0",
"axios": "^1.6.0",
"joi": "^17.11.0",
"@fastify/multipart": "^8.0.0"
}
}
*Python渚濊禆锛?
fastapi==0.115.0
uvicorn==0.30.0
pandas==2.2.0
openpyxl==3.1.0
chardet==5.2.0
python-multipart==0.0.9
涔濄€侀」鐩<EFBFBD><EFBFBD>鐞?
9.1 鍥㈤槦閰嶇疆
| 瑙掕壊 | 浜烘暟 | 鑱岃矗 |
|---|---|---|
| 鍓嶇<EFBFBD>寮€鍙? | 1浜? | React + AG Grid + UI |
| Node.js鍚庣<E98D9A> | 1浜? | BFF + LLM闆嗘垚 + Prompt宸ョ▼ |
| Python寮€鍙? | 1浜? | FastAPI + DataFrame + AST妫€鏌? |
| 鎬昏<EFBFBD> | *3浜? | 3鍛<EFBFBD>紙15澶╋級 |
9.2 娌熼€氭満鍒?
- 姣忔棩绔欎細锛?5鍒嗛挓锛屽悓姝ヨ繘搴﹀拰闂<E68BB0><E99782>
- 鍏抽敭妫€鏌ョ偣锛欴ay 5銆?銆?0銆?4
- 闂<EFBFBD><EFBFBD>鍗囩骇锛氶樆濉為棶棰?灏忔椂鍐呭崌绾?
- 鏂囨。鏇存柊锛氭瘡鏃ユ洿鏂板紑鍙戣<EFBFBD>褰?
9.3 浠g爜绠$悊
*鍒嗘敮绛栫暐锛?
main (绋冲畾鐗?
鈹斺攢鈹€ develop (寮€鍙戠増)
鈹溾攢鈹€ feature/tool-c-frontend
鈹溾攢鈹€ feature/tool-c-backend
鈹斺攢鈹€ feature/tool-c-python
*鎻愪氦瑙勮寖锛?
feat: 鏂板<E98F82>AI浠g爜鐢熸垚鍔熻兘
fix: 淇<><E6B787>琛ㄦ牸鍒锋柊Bug
test: 澧炲姞AST妫€鏌ユ祴璇曠敤渚?
docs: 鏇存柊寮€鍙戞枃妗?
鍗併€佹€荤粨
鏍稿績鎴愬姛瑕佺礌
- 鉁?AI浠g爜璐ㄩ噺锛氭垚鍔熺巼 > 80%锛堟牳蹇冨亣璁撅級
- 鉁?**鎬ц兘鍙<E58598>帴鍙?*锛氱<E9949B>鍒扮<E98D92> < 16绉?
- 鉁?**浜や簰绠€鍗?*锛氱敤鎴锋棤闇€鏂囨。灏辫兘鐢?
椋庨櫓鎺у埗
- 鉁?**蹇<>€熷け璐?*锛?澶╅獙璇丄I鑳藉姏锛屼笉琛岀珛鍗砅ivot
- 鉁?**鍔″疄鎶€鏈?*锛欽SON涓嶇敤Arrow锛屽唴瀛樹笉鐢≧edis
- 鉁?**闄嶇骇鏂规<E98F82>**锛氬噯澶囧ソ妯℃澘搴撱€佹壒澶勭悊绛塒lan B
鏃堕棿鑺傜偣
- Week 1锛氬熀纭€鏋舵瀯锛?澶╋級
- Week 2锛氭牳蹇冨姛鑳斤紙5澶╋級
- Week 3锛氫紭鍖栨祴璇曪紙5澶╋級
- **鎬昏<E98EAC>**锛?5涓<35>伐浣滄棩
馃摑 鏂囨。淇<E38082><E6B787>璁板綍
V1.3锛?025-12-06锛? 鍙戠幇鐜版湁Python鏈嶅姟 猸?閲嶅ぇ鍙戠幇
**淇<><E6B787>鍐呭<E98D90>**锛氭<E9949B>鏌ョ郴缁熷彂鐜板凡鏈塒ython寰<6E>湇鍔★紝涓嶉渶瑕侀噸澶嶅紑鍙戯細
淇<EFBFBD><EFBFBD>1锛氬<EFBFBD>鐢ㄧ幇鏈塒ython鏈嶅姟锛屼笉閲嶅<EFBFBD>閫犺疆 猸愨瓙猸愨瓙猸?
- 閲嶅ぇ鍙戠幇锛氱郴缁熷凡鏈?
extraction_service/锛團astAPI + Pandas + openpyxl锛? - 鐜版湁鍔熻兘锛?
- 鉁?PDF/Docx/Txt鏂囨。鎻愬彇锛圥yMuPDF + Mammoth锛?
- 鉁?Pandas銆乷penpyxl銆乧hardet銆乴angdetect宸插畨瑁?
- 鉁?FastAPI妗嗘灦宸茶繍琛岋紙绔<E7B499>彛8000锛?
- 鉁?Node.js宸叉湁ExtractionClient闆嗘垚
- **鏂板<E98F82>鏂规<E98F82>**锛?
- 鉁?鎵╁睍鐜版湁鏈嶅姟锛屾坊鍔?
/api/dc/execute绔<>偣 - 鉁?鏂板<E98F82>
dc_executor.py妯″潡锛圓ST妫€鏌?+ 浠g爜鎵ц<E98EB5>锛? - 鉁?澶嶇敤ExtractionClient妯″紡璋冪敤
- 鉁?鎵╁睍鐜版湁鏈嶅姟锛屾坊鍔?
- **閬垮厤閲嶅<E996B2>**锛?
- 鉂?涓嶉渶瑕佹柊寤篜ython椤圭洰
- 鉂?涓嶉渶瑕侀噸鏂板畨瑁呬緷璧?
- 鉂?涓嶉渶瑕侀噸鏂板啓HTTP璋冪敤閫昏緫
V1.2锛?025-12-06锛? Python鎵ц<E98EB5>鐜<EFBFBD><E9909C> + 澶嶆潅鍦烘櫙 鈿狅笍 鏍稿績鍔熻兘
**淇<><E6B787>鍐呭<E98D90>**锛氭牴鎹<E789B4>敤鎴峰弽棣堬紝鏄庣‘Python浠g爜鎵ц<E98EB5>鏄<EFBFBD>牳蹇冨姛鑳斤細
淇<EFBFBD><EFBFBD>1锛歅ython鎵ц<EFBFBD>鏄<EFBFBD>牳蹇冿紝涓嶆槸鍙<EFBFBD>€?猸愨瓙猸愨瓙猸?
- **鍘熼敊璇?*锛氳<E9949B>"MVP闃舵<E99783>鍙<EFBFBD>兘涓嶉渶瑕丳ython寰<6E>湇鍔?
- **宸蹭慨姝?锛?Python浠g爜鎵ц<EFBFBD>鏄<EFBFBD>伐鍏稢鐨勬牳蹇冧环鍊硷紝蹇呴』瀹炵幇
- **鏂板<E98F82>鍐呭<E98D90>**锛?
- Day 1澧炲姞Python鐜<6E><E9909C>鎼<EFBFBD>缓
- 鏂板<EFBFBD>PythonExecutorService锛圢ode.js 鈫?Python閫氫俊锛?
- 鏂板<EFBFBD>executor.py锛圥andas浠g爜鎵ц<E98EB5>鍣<EFBFBD>級
- 鎶€鏈<EFBFBD>柟妗堬細Node.js child_process璋冪敤Python鑴氭湰
淇<EFBFBD><EFBFBD>2锛氭祴璇曞満鏅<EFBFBD>粠绠€鍗曞埌澶嶆潅 鉁?
- **鍘熼棶棰?*锛?0涓<30>祴璇曞満鏅<E6BA80>繃浜庣畝鍗?
- **宸蹭慨姝?*锛?5涓<35>湡瀹炲尰鐤楁暟鎹<E69A9F>竻娲楀満鏅?
- 馃煝 鍩虹<E98DA9>鍦烘櫙5涓<35>細鍗曟<E98D97>楠ゆ搷浣?
- 馃煛 涓<>瓑鍦烘櫙5涓<35>細澶氭<E6BEB6>楠ゃ€佽法鍒楅€昏緫
- 馃敶 楂樼骇鍦烘櫙5涓<35>細鍒嗙粍鑱氬悎銆佹椂闂村簭鍒椼€佸尰瀛﹁<E7809B>鍒?
- 鏂板<EFBFBD>鍦烘櫙锛?
- 澶嶆潅鏉′欢閫昏緫锛堢敓瀛樻椂闂磋<EFBFBD>绠楋級
- 鍖诲<EFBFBD>瑙勫垯寮曟搸锛堣倽鍔熻兘鍒嗙骇锛?
- 鏃堕棿搴忓垪鍒嗘瀽锛堟寚鏍囧彉鍖栫巼锛?
- 鏂囨湰鎻愬彇锛圱NM鍒嗘湡锛?
- 瀛楃<EFBFBD>涓插<EFBFBD>鐞嗭紙琛€鍘嬫媶鍒嗭級
淇<EFBFBD><EFBFBD>3锛氶獙鏀舵爣鍑嗗垎灞?鉁?
- **鍘熸爣鍑?*锛氭€讳綋鎴愬姛鐜?> 80%
- **鏂版爣鍑?*锛?
- 鍩虹<EFBFBD>鍦烘櫙鎴愬姛鐜?> 90%
- 涓<EFBFBD>瓑鍦烘櫙鎴愬姛鐜?> 80%
- 楂樼骇鍦烘櫙鎴愬姛鐜?> 60%
- 鎬讳綋鎴愬姛鐜?> 80%锛?2/15鍦烘櫙锛?
淇<EFBFBD><EFBFBD>4锛氭牳蹇冨亣璁鹃獙璇?鉁?
- 鏂板<EFBFBD>H2锛歅ython浠g爜鎵ц<EFBFBD>鐜<EFBFBD><EFBFBD>绋冲畾鍙<EFBFBD>潬
- 淇<EFBFBD>敼H1锛氫粠"鐢熸垚浠g爜"鏀逛负"鐢熸垚浠g爜骞舵垚鍔熸墽琛?
- 寮鸿皟锛欰I鐢熸垚浠g爜 + 鐪熷疄鎵ц<E98EB5> + 琛ㄦ牸鍒锋柊鏄<E69F8A>樊寮傚寲浠峰€?
V1.1锛?025-12-06锛? 鏋舵瀯鍚堣<E98D9A>鎬т慨姝?鈿狅笍 閲嶈<E996B2>
**淇<><E6B787>鍐呭<E98D90>**锛氭牴鎹<E789B4>敤鎴蜂弗鑲冩彁閱掞紝淇<E7B49D><E6B787>浠ヤ笅杩濆弽瑙勮寖鐨勯棶棰橈細
淇<EFBFBD><EFBFBD>1锛氬己鍒跺<EFBFBD>鐢ㄥ钩鍙拌兘鍔?鉁?
- **鍘熼敊璇?*锛氬缓璁<E7BC93>嚜宸卞疄鐜癝ession绠$悊銆佸瓨鍌ㄣ€佹棩蹇?
- **宸蹭慨姝?*锛氬己鍒朵娇鐢╜storage
,logger,cache,prisma,LLMFactory` - 褰卞搷绔犺妭锛氭墍鏈塂ay 1-15鐨勪唬鐮佺ず渚?
淇<EFBFBD><EFBFBD>2锛歋ession瀛樺偍鏂瑰紡 鉁?
- **鍘熼敊璇?*锛氬缓璁<E7BC93>敤
Map<sessionId, data>鍐呭瓨缂撳瓨 - **宸蹭慨姝?*锛歋ession瀛樻暟鎹<E69A9F>簱锛坄dc_tool_c_sessions`琛<>級
- 鍘熷洜锛氳繚鍙嶄簯鍘熺敓瑙勮寖绗?鏉★紙绂佹<E7BB82>鍐呭瓨缂撳瓨锛?
淇<EFBFBD><EFBFBD>3锛氭枃浠跺す缁撴瀯 鉁?
- **鍘熼敊璇?*锛氬缓璁<E7BC93>垱寤篳python-service/
銆乣node-service/瀛愭枃浠跺す - **宸蹭慨姝?*锛氶伒寰猼ool-b缁撴瀯锛坄services/
,controllers/,routes/`锛? - **鍙傝€?*锛歚backend/src/modules/dc/tool-b/`
淇<EFBFBD><EFBFBD>4锛氭妧鏈<EFBFBD>爤璇存槑 鉁?
- **鍘熼敊璇?*锛氭湭寮鸿皟澶嶇敤鐜版湁鑳藉姏
- **宸蹭慨姝?*锛氭槑纭<E6A791>爣娉?宸叉湁"銆?澶嶇敤骞冲彴鑳藉姏"
- **鏂板<E98F82>**锛氫簯鍘熺敓寮€鍙戣<E98D99>鑼冩<E991BC>鏌ユ竻鍗?
淇<EFBFBD><EFBFBD>5锛氫唬鐮佺ず渚?鉁?
- **鍘熼敊璇?*锛欴ay 1-5鐨勪唬鐮佺ず渚嬫湭浣撶幇骞冲彴鏈嶅姟
- **宸蹭慨姝?*锛氭墍鏈変唬鐮佺ず渚嬮兘浣跨敤
import { storage } from '@/common/storage'绛? - **鏂板<E98F82>**锛氬父瑙侀敊璇<E6958A>ず渚嬶紙鉂?涓ョ<E6B693>锛?
鏂板<EFBFBD>绔犺妭 鉁?
- **寮€鍙戝墠蹇呰<E8B987>**锛氬己璋冧笉瑕侀噸澶嶉€犺疆瀛?
- **浜戝師鐢熻<E990A2>鑼冨己鍒惰<E98D92>姹?*锛氬垪鍑?鏉℃牳蹇冭<E8B987>鑼?
- 甯歌<EFBFBD>閿欒<EFBFBD>绀轰緥锛氬睍绀?涓<>弗绂佺殑閿欒<E996BF>鍐欐硶
鏂囨。鐘舵€侊細 鉁?宸插畬鎴愶紙V1.1 鏋舵瀯鍚堣<E98D9A>鎬т慨姝g増锛?
涓嬩竴姝ワ細 鍥㈤槦Review 鈫?涓ユ牸鎸夎<E98EB8>鑼冨紑鍙?
璐熻矗浜猴細 椤圭洰缁忕悊
*鍒涘缓鏃ユ湡锛? 2025-12-06
*淇<EFBFBD><EFBFBD>鏃ユ湡锛? 2025-12-06锛堟灦鏋勫悎瑙勬€т慨姝o級
鈿狅笍 閲嶈<E996B2>鎻愰啋锛?
- 寮€鍙戝墠蹇呴』闃呰<EFBFBD>锛歚docs/04-寮€鍙戣<E98D99>鑼?08-浜戝師鐢熷紑鍙戣<E98D99>鑼?md`
- 鍙傝€冪幇鏈夊疄鐜帮細
backend/src/modules/dc/tool-b/ - 绂佹<EFBFBD>杩濆弽瑙勮寖锛氬唴瀛樼紦瀛樸€佹湰鍦版枃浠跺瓨鍌ㄣ€侀噸澶嶅疄鐜板钩鍙拌兘鍔?