Files
AIclinicalresearch/docs/03-业务模块/RVW-稿件审查系统/04-开发计划/RVW模块迁移计划.md
HaHafeng 1b53ab9d52 feat(aia): Complete AIA V2.0 with universal streaming capabilities
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%)
2026-01-14 19:15:01 +08:00

25 KiB
Raw Blame History

RVW绋夸欢瀹℃煡妯″潡杩佺Щ璁″垝锛坴2.1 - 绋冲畾杩佺Щ鐗堬級

*鏂囨。鐗堟湰锛? v2.1
*鍒涘缓鏃ユ湡锛? 2026-01-07
鏈€鍚庢洿鏂帮細 2026-01-07
缁存姢鑰咃細 寮€鍙戝洟闃? *鏂囨。鐩<EFBFBD>殑锛? 灏嗙ǹ浠跺<E6B5A0>鏌ュ姛鑳戒粠鏃ф灦鏋勫畨鍏ㄨ縼绉诲埌鏂版灦鏋勶紝鍚屾椂鏁村悎MVP鏍稿績闇€姹?


馃搵 椤圭洰姒傝堪

1. 鑳屾櫙

绋夸欢瀹℃煡鍔熻兘鏄?025-10-30锛圖ay 30锛夌嫭绔嬪紑鍙戠殑鍔熻兘妯″潡锛岀洰鍓嶄綅浜?backend/src/legacy/ 鍜?frontend/<>綍涓<E7B68D>€傜幇闇€瑕侊細

  1. 鏋舵瀯杩佺Щ锛氳縼绉诲埌鏍囧噯鐨勬ā鍧楃洰褰曠粨鏋勶紙modules/rvw锛?2. 鍔熻兘鍗囩骇锛氭暣鍚堛€婃櫤鑳芥湡鍒婂<EFBFBD>绋跨郴缁烳VP浜у搧闇€姹傛枃妗€嬬殑鏍稿績鍔熻兘

2. 杩佺Щ鍘熷垯

鍘熷垯 璇存槑
绋冲畾浼樺厛 姣忎釜Phase瀹屾垚鍚庡繀椤婚€氳繃娴嬭瘯楠岃瘉
瀹夊叏鍙<EFBFBD> 鏁版嵁搴撹縼绉诲墠蹇呴』澶囦唤锛屾敮鎸佸洖婊?
闃舵<EFBFBD>楠岃瘉 姣忎釜Phase鏈夋槑纭<EFBFBD>殑楠屾敹鏍囧噯
鍚戝悗鍏煎<EFBFBD> 淇濈暀鏃<EFBFBD>PI杩囨浮鏈燂紝涓嶅奖鍝嶇幇鏈夊姛鑳?
*娓愯繘寮? 鍏堟牳蹇冨悗鎵╁睍锛屽厛鍚庣<EFBFBD>鍚庡墠绔?

3. 鍔熻兘鑼冨洿

鍔熻兘 <EFBFBD><EFBFBD>寮€鍙? 鏁版嵁搴撴敮鎾? 璇存槑
鏍稿績AI璇勪及 鉁? 鉁? 绋跨害瑙勮寖鎬?鏂规硶瀛?
鎵归噺涓婁紶 鉁? 鉁? 澶氭枃浠朵笂浼?
*瀹$ǹ宸ヤ綔鍙? 鉁? 鉁? 瀹借〃甯冨眬+绛涢€?
鏅鸿兘浣撻€夋嫨 鉁? 鉁? <EFBFBD>€?涓<>垨2涓?
鎵归噺鎿嶄綔 鉁? 鉁? 鎵归噺杩愯<EFBFBD>瀹℃煡
*鐘舵€佺瓫閫? 鉁? 鉁? 鍏ㄩ儴/寰呭<E5AFB0>鐞?宸插畬鎴?
PDF鎶ュ憡瀵煎嚭 鉁? 鉁? 浼樺寲鐜版湁鍔熻兘
PICO鍗 鈴革笍 鉁? *鏆備笉寮€鍙戯紝鏁版嵁搴撻<EFBFBD>鐣?
绯荤粺璁剧疆 鈴革笍 鉁? *鏆備笉寮€鍙戯紝鏁版嵁搴撻<EFBFBD>鐣?
鍘嗗彶褰掓。 鈴革笍 鉁? *鏆備笉寮€鍙戯紝鏁版嵁搴撻<EFBFBD>鐣?
鐧诲綍椤甸潰 鈴革笍 - 鏆備笉寮€鍙?

4. 鏅鸿兘浣撻€夋嫨璇存槑

鐢ㄦ埛鍙<EFBFBD>互鐏垫椿閫夋嫨杩愯<EFBFBD>鐨勬櫤鑳戒綋锛?

閫夐」 A: 鍙<>€夋嫨銆岀ǹ绾﹁<E7BBBE>鑼冩€ф櫤鑳戒綋銆?    鈫?鍙<>繍琛岃<E7909B>鑼冩€ц瘎浼?閫夐」 B: 鍙<>€夋嫨銆屾柟娉曞<E5A889>缁熻<E7BC81>鏅鸿兘浣撱€?    鈫?鍙<>繍琛屾柟娉曞<E5A889>璇勪及
閫夐」 C: 鍚屾椂閫夋嫨涓や釜鏅鸿兘浣?           鈫?鍚屾椂杩愯<E69DA9>涓ら」璇勪及锛堥粯璁わ級

馃搳 鏁版嵁搴撹<E690B4>璁★紙瀹屾暣鐗堬紝鏀<E7B49D>拺鏈<E68BBA>潵鎵╁睍锛?

1. 鏈熷垔閰嶇疆琛<E79686>紙棰勭暀锛屾殏涓嶄娇鐢<E5A887>

// review_schema

model JournalConfig {
  id            String   @id @default(uuid())
  name          String                          // 鏈熷垔鍚嶇О
  logoUrl       String?  @map("logo_url")       // Logo URL锛堥<E9949B>鐣欙級
  defaultModel  String   @default("deepseek-v3") @map("default_model")
  settings      Json?                           // 鍏朵粬閰嶇疆锛堥<E9949B>鐣欙級
  createdAt     DateTime @default(now()) @map("created_at")
  updatedAt     DateTime @updatedAt @map("updated_at")
  
  reviewTasks   ReviewTask[]
  
  @@map("journal_configs")
  @@schema("review_schema")
}

2. 瀹ǹ浠诲姟琛<E5A79F>紙鎵╁睍鐗堬級

model ReviewTask {
  id                String    @id @default(uuid())
  userId            String    @map("user_id")
  journalId         String?   @map("journal_id")       // 棰勭暀锛氭湡鍒婂叧鑱?  
  // 鏂囦欢淇℃伅
  fileName          String    @map("file_name")
  fileSize          Int       @map("file_size")
  filePath          String?   @map("file_path")
  extractedText     String    @map("extracted_text")
  wordCount         Int?      @map("word_count")
  authorName        String?   @map("author_name")      // 棰勭暀锛氫綔鑰呮彁鍙?  
  // 鐘舵€佺<E282AC>鐞?  status            String    @default("pending")
  // 鉁?鏅鸿兘浣撻€夋嫨锛氬彲閫?涓<>垨2涓?  selectedAgents    String[]  @default(["editorial", "methodology"]) @map("selected_agents")
  
  // 璇勪及缁撴灉
  editorialReview   Json?     @map("editorial_review")
  methodologyReview Json?     @map("methodology_review")
  overallScore      Float?    @map("overall_score")
  
  // 缁撴灉鎽樿<E98EBD>锛堢敤浜庡垪琛ㄥ睍绀猴級
  editorialScore    Float?    @map("editorial_score")
  methodologyStatus String?   @map("methodology_status") // pass/warn/fail
  
  // 棰勭暀锛歅ICO鎻愬彇锛堟殏涓嶄娇鐢<E5A887>級
  picoExtract       Json?     @map("pico_extract")
  
  // 鍏冩暟鎹?  modelUsed         String?   @map("model_used")
  startedAt         DateTime? @map("started_at")
  completedAt       DateTime? @map("completed_at")
  durationSeconds   Int?      @map("duration_seconds")
  errorMessage      String?   @map("error_message")
  
  // 棰勭暀锛氬綊妗e姛鑳斤紙鏆備笉浣跨敤锛?  isArchived        Boolean   @default(false) @map("is_archived")
  archivedAt        DateTime? @map("archived_at")
  
  createdAt         DateTime  @default(now()) @map("created_at")
  updatedAt         DateTime  @updatedAt @map("updated_at")
  
  // 鍏宠仈
  user              users     @relation(fields: [userId], references: [id], onDelete: Cascade)
  journal           JournalConfig? @relation(fields: [journalId], references: [id])

  @@index([userId])
  @@index([journalId])
  @@index([status])
  @@index([createdAt])
  @@index([isArchived])
  @@map("review_tasks")
  @@schema("review_schema")
}

3. 瀛楁<E7809B>璇存槑

瀛楁<EFBFBD> <EFBFBD><EFBFBD>浣跨敤 棰勭暀鐢ㄩ€?
journalId 鉂? 绯荤粺璁剧疆锛氭湡鍒婂叧鑱?
authorName 鉂? <EFBFBD>姩鎻愬彇浣滆€呭悕
selectedAgents 鉁? 鐢ㄦ埛閫夋嫨鐨勬櫤鑳戒綋
editorialScore 鉁? 鍒楄〃鏄剧ず瑙勮寖鎬у垎鏁?
methodologyStatus 鉁? 鍒楄〃鏄剧ず鏂规硶瀛︾姸鎬?
picoExtract 鉂? PICO鍗墖鏁版嵁
isArchived 鉂? 鍘嗗彶褰掓。鍔熻兘
archivedAt 鉂? 褰掓。鏃堕棿

馃搵 瀹夊叏杩佺Щ绛栫暐

1. 杩佺Щ鍓嶅噯澶?

# 1. 澶囦唤鏁版嵁搴?pg_dump -h localhost -U postgres -d airesearch -F c -f backup_before_rvw_migration.dump

# 2. 璁板綍褰撳墠鏁版嵁閲?SELECT COUNT(*) FROM public.review_tasks;

# 3. 瀵煎嚭鍏抽敭鏁版嵁锛堝彲閫夛級
COPY public.review_tasks TO '/tmp/review_tasks_backup.csv' WITH CSV HEADER;

2. 鍥炴粴鏂规<E98F82>

# 濡傛灉杩佺Щ澶辫触锛屽洖婊氭暟鎹<E69A9F>
pg_restore -h localhost -U postgres -d airesearch -c backup_before_rvw_migration.dump

# 濡傛灉鍙<E78189>渶瑕佸洖婊歋chema杩佺Щ
ALTER TABLE review_schema.review_tasks SET SCHEMA public;
DROP SCHEMA review_schema;

3. 闃舵<E99783>鎬ч獙璇?

姣忎釜Phase瀹屾垚鍚庡繀椤婚€氳繃浠ヤ笅楠岃瘉锛?

Phase 楠岃瘉鍐呭<EFBFBD> 楠屾敹鏍囧噯
Phase 1 鍚庣<EFBFBD>API娴嬭瘯 鎵€鏈堿PI杩斿洖姝锛屾棩蹇楁棤ERROR
Phase 2 鏁版嵁搴撹縼绉? 鏁版嵁瀹屾暣锛屾煡璇㈡<EFBFBD>甯革紝绱㈠紩鏈夋晥
Phase 3 鍓嶇<EFBFBD>鍔熻兘娴嬭瘯 鏍稿績娴佺▼閫氶『锛屾棤鐧藉睆/鎶ラ敊
Phase 4 闆嗘垚娴嬭瘯 <EFBFBD>埌绔<EFBFBD>祦绋嬫<EFBFBD>甯?
Phase 5 楠屾敹娴嬭瘯 绗﹀悎MVP楠屾敹鏍囧噯

馃搵 寮€鍙戜换鍔℃竻鍗?

Phase 1锛氬悗绔<E68297>ā鍧楄縼绉伙紙2澶╋級

Day 1 涓婂崍锛氬垱寤烘ā鍧楃粨鏋?+ 澶嶇敤鏍稿績浠g爜

1.1 鍒涘缓鐩<E7BC93>綍缁撴瀯

backend/src/modules/rvw/
鈹溾攢鈹€ routes/
鈹?  鈹斺攢鈹€ index.ts                 # 璺<>敱瀹氫箟
鈹溾攢鈹€ controllers/
鈹?  鈹斺攢鈹€ reviewController.ts      # 鎺у埗鍣?鈹溾攢鈹€ services/
鈹?  鈹溾攢鈹€ reviewService.ts         # 涓绘湇鍔★紙澶嶇敤+鎵╁睍锛?鈹?  鈹溾攢鈹€ editorialService.ts      # 绋跨害璇勪及锛堝<E9949B><EFBFBD>級
鈹?  鈹斺攢鈹€ methodologyService.ts    # 鏂规硶瀛﹁瘎浼帮紙澶嶇敤锛?鈹溾攢鈹€ types/
鈹?  鈹斺攢鈹€ index.ts                 # 绫诲瀷瀹氫箟
鈹溾攢鈹€ prompts/
鈹?  鈹溾攢鈹€ editorial_system.txt     # 绋跨害Prompt
鈹?  鈹斺攢鈹€ methodology_system.txt   # 鏂规硶瀛<E7A1B6>rompt
鈹斺攢鈹€ index.ts                     # 妯″潡鍏ュ彛
  • 1.1.1 鍒涘缓鐩<E7BC93>綍缁撴瀯
  • 1.1.2 澶嶅埗 reviewEditorialStandards() 鈫?editorialService.ts
  • 1.1.3 澶嶅埗 reviewMethodology() 鈫?methodologyService.ts
  • 1.1.4 澶嶅埗 parseJSONFromLLMResponse() 鈫?utils.ts
  • 1.1.5 澶嶅埗 Prompt 鏂囦欢鍒版ā鍧楀唴

*1.2 浜戝師鐢熸敼閫?

  • 1.2.1 鏇挎崲 console.log 鈫?logger
  • 1.2.2 绉婚櫎 Mock鐢ㄦ埛ID锛岄泦鎴怞WT璁よ瘉
  • 1.2.3 浣跨敤 process.env 閰嶇疆

Day 1 涓嬪崍锛氭櫤鑳戒綋閫夋嫨閫昏緫

1.3 鏅鸿兘浣撻€夋嫨瀹炵幇

// types/index.ts
export type AgentType = 'editorial' | 'methodology';

export interface RunReviewParams {
  taskId: string;
  agents: AgentType[];  // 鍙<>€?涓<>垨2涓?}

// services/reviewService.ts
async function runReview(params: RunReviewParams) {
  const { taskId, agents } = params;
  
  // 楠岃瘉锛氳嚦灏戦€夋嫨1涓<31>櫤鑳戒綋
  if (agents.length === 0) {
    throw new Error('璇疯嚦灏戦€夋嫨涓€涓<E282AC>櫤鑳戒綋');
  }
  
  // 鏇存柊浠诲姟鐘舵€?  await prisma.reviewTask.update({
    where: { id: taskId },
    data: { 
      status: 'reviewing',
      selectedAgents: agents,
      startedAt: new Date()
    }
  });
  
  // 鍙<>繍琛岄€変腑鐨勬櫤鑳戒綋
  let editorialResult = null;
  let methodologyResult = null;
  
  if (agents.includes('editorial')) {
    editorialResult = await editorialService.review(taskId);
  }
  
  if (agents.includes('methodology')) {
    methodologyResult = await methodologyService.review(taskId);
  }
  
  // 璁$畻缁煎悎鍒嗘暟
  const overallScore = calculateOverallScore(editorialResult, methodologyResult, agents);
  
  // 鏇存柊缁撴灉
  await prisma.reviewTask.update({
    where: { id: taskId },
    data: {
      status: 'completed',
      editorialReview: editorialResult,
      methodologyReview: methodologyResult,
      editorialScore: editorialResult?.overall_score,
      methodologyStatus: getMethodologyStatus(methodologyResult),
      overallScore,
      completedAt: new Date(),
      durationSeconds: calculateDuration(taskId)
    }
  });
}

// 鏍规嵁閫夋嫨鐨勬櫤鑳戒綋璁$畻缁煎悎鍒嗘暟
function calculateOverallScore(editorial: any, methodology: any, agents: AgentType[]) {
  if (agents.length === 2 && editorial && methodology) {
    // 涓や釜閮介€夛細40% + 60%
    return editorial.overall_score * 0.4 + methodology.overall_score * 0.6;
  } else if (agents.includes('editorial') && editorial) {
    // 鍙<>€夎<E282AC>鑼冩€?    return editorial.overall_score;
  } else if (agents.includes('methodology') && methodology) {
    // 鍙<>€夋柟娉曞<E5A889>
    return methodology.overall_score;
  }
  return null;
}
  • 1.3.1 瀹炵幇鏅鸿兘浣撻€夋嫨绫诲瀷瀹氫箟
  • 1.3.2 瀹炵幇 runReview() 鍑芥暟
  • 1.3.3 瀹炵幇缁煎悎鍒嗘暟璁$畻閫昏緫
  • 1.3.4 瀹炵幇鏂规硶瀛︾姸鎬佸垽鏂<E59EBD>紙pass/warn/fail锛?

Day 2 涓婂崍锛氭壒閲忔搷浣?+ API鎵╁睍

1.4 鎵归噺杩愯<E69DA9>瀹炵幇

// services/reviewService.ts
async function batchRunReview(params: BatchRunParams) {
  const { taskIds, agents } = params;
  
  // 闄愬埗骞跺彂鏁?  const MAX_CONCURRENT = 5;
  const results = [];
  
  for (let i = 0; i < taskIds.length; i += MAX_CONCURRENT) {
    const batch = taskIds.slice(i, i + MAX_CONCURRENT);
    const batchResults = await Promise.allSettled(
      batch.map(taskId => runReview({ taskId, agents }))
    );
    results.push(...batchResults);
  }
  
  return results;
}
  • 1.4.1 瀹炵幇鎵归噺杩愯<E69DA9>鎺ュ彛
  • 1.4.2 瀹炵幇骞跺彂鎺у埗锛堟渶澶?涓<>
  • 1.4.3 瀹炵幇閿欒<E996BF>澶勭悊锛堝崟涓<E5B49F>け璐ヤ笉褰卞搷鍏朵粬锛? 1.5 API璺<49>敱瀹氫箟
// routes/index.ts
export default async function rvwRoutes(fastify: FastifyInstance) {
  // 浠诲姟绠$悊
  fastify.post('/tasks', reviewController.createTask);          // 鍒涘缓/涓婁紶
  fastify.get('/tasks', reviewController.getTaskList);          // 鍒楄〃锛堢瓫閫夛級
  fastify.get('/tasks/:taskId', reviewController.getTaskDetail); // 璇︽儏
  fastify.get('/tasks/:taskId/report', reviewController.getTaskReport); // 鎶ュ憡
  fastify.delete('/tasks/:taskId', reviewController.deleteTask); // 鍒犻櫎
  
  // 杩愯<E69DA9>瀹℃煡锛堟牳蹇冨姛鑳斤級
  fastify.post('/tasks/:taskId/run', reviewController.runReview);     // 鍗曚釜杩愯<E69DA9>
  fastify.post('/tasks/batch/run', reviewController.batchRunReview);  // 鎵归噺杩愯<E69DA9>
}
  • 1.5.1 瀹炵幇璺<E5B987>敱瀹氫箟
  • 1.5.2 瀹炵幇鎺у埗鍣ㄦ柟娉?- [ ] 1.5.3 娣诲姞璇锋眰楠岃瘉

Day 2 涓嬪崍锛氭敞鍐岃矾鐢?+ Phase 1 楠岃瘉

*1.6 娉ㄥ唽鏂拌矾鐢?

// backend/src/index.ts
import rvwRoutes from './modules/rvw/routes/index.js';

// 娉ㄥ唽鏂拌矾鐢憋紙v2锛?await fastify.register(rvwRoutes, { prefix: '/api/v1/rvw' });
logger.info('鉁?RVW绋夸欢瀹℃煡璺<E785A1>敱宸叉敞鍐? /api/v1/rvw');

// 淇濈暀鏃ц矾鐢憋紙鍏煎<E98D8F>锛?await fastify.register(reviewRoutes, { prefix: '/api/v1' });
logger.info('鉁?Legacy瀹ǹ璺<C7B9>敱淇濈暀: /api/v1/review');
  • 1.6.1 娉ㄥ唽鏂拌矾鐢?- [ ] 1.6.2 淇濈暀鏃ц矾鐢卞吋瀹? 1.7 Phase 1 楠岃瘉娴嬭瘯
### 1. 鍒涘缓浠诲姟
POST {{baseUrl}}/api/v1/rvw/tasks
Content-Type: multipart/form-data

# file: test.docx

### 2. 杩愯<E69DA9>瀹℃煡锛堝彧閫夎<E996AB>鑼冩€э級
POST {{baseUrl}}/api/v1/rvw/tasks/{{taskId}}/run
Content-Type: application/json

{ "agents": ["editorial"] }

### 3. 杩愯<E69DA9>瀹℃煡锛堝彧閫夋柟娉曞<E5A889>锛?POST {{baseUrl}}/api/v1/rvw/tasks/{{taskId}}/run
Content-Type: application/json

{ "agents": ["methodology"] }

### 4. 杩愯<E69DA9>瀹℃煡锛堜袱涓<E8A2B1>兘閫夛級
POST {{baseUrl}}/api/v1/rvw/tasks/{{taskId}}/run
Content-Type: application/json

{ "agents": ["editorial", "methodology"] }

### 5. 鎵归噺杩愯<E69DA9>
POST {{baseUrl}}/api/v1/rvw/tasks/batch/run
Content-Type: application/json

{
  "taskIds": ["id1", "id2", "id3"],
  "agents": ["editorial", "methodology"]
}

### 6. 鑾峰彇浠诲姟鍒楄〃
GET {{baseUrl}}/api/v1/rvw/tasks?status=pending&limit=10

### 7. 鑾峰彇鎶ュ憡
GET {{baseUrl}}/api/v1/rvw/tasks/{{taskId}}/report

*Phase 1 楠屾敹鏍囧噯锛?

娴嬭瘯椤? 棰勬湡缁撴灉 閫氳繃
鍒涘缓浠诲姟 杩斿洖taskId锛岀姸鎬乸ending 猬?
<EFBFBD>€夎<EFBFBD>鑼冩€? <EFBFBD>湁editorialReview鏈夊€? 猬?
<EFBFBD>€夋柟娉曞<EFBFBD> <EFBFBD>湁methodologyReview鏈夊€? 猬?
涓や釜閮介€? 涓や釜Review閮芥湁鍊? 猬?
鎵归噺杩愯<EFBFBD> 澶氫釜浠诲姟閮藉畬鎴? 猬?
<EFBFBD>PI鍏煎<EFBFBD> /api/v1/review/* 姝e父 猬?
  • 1.7.1 缂栧啓娴嬭瘯鐢ㄤ緥
  • 1.7.2 鎵ц<E98EB5>娴嬭瘯
  • 1.7.3<><E6B787><EFBFBD><E99782>
  • 1.7.4<><E7BAAD>Phase 1閫氳繃

Phase 2锛氭暟鎹<E69A9F>簱Schema杩佺Щ锛?.5澶╋級

杩佺Щ鍓嶏細澶囦唤

  • 2.1 澶囦唤鏁版嵁搴? ```bash pg_dump -h localhost -U postgres -d airesearch -F c -f backup_phase2.dump

    
    
  • 2.2 璁板綍褰撳墠鏁版嵁

    SELECT COUNT(*) FROM public.review_tasks;
    

杩佺Щ鎵ц<EFBFBD>

  • 2.3 鍒涘缓杩佺ЩSQL

    -- 1. 鍒涘缓鏂癝chema
    CREATE SCHEMA IF NOT EXISTS review_schema;
    
    -- 2. 鍒涘缓鏈熷垔閰嶇疆琛<E79686>紙棰勭暀锛?  CREATE TABLE review_schema.journal_configs (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      name VARCHAR(255) NOT NULL,
      logo_url TEXT,
      default_model VARCHAR(50) DEFAULT 'deepseek-v3',
      settings JSONB,
      created_at TIMESTAMPTZ DEFAULT NOW(),
      updated_at TIMESTAMPTZ DEFAULT NOW()
    );
    
    -- 3. 杩佺Щreview_tasks琛ㄥ埌鏂癝chema
    ALTER TABLE public.review_tasks SET SCHEMA review_schema;
    
    -- 4. 娣诲姞鏂板瓧娈碉紙鏀<E7B499>寔鏈<E5AF94>潵鎵╁睍锛?  ALTER TABLE review_schema.review_tasks
      ADD COLUMN IF NOT EXISTS journal_id UUID REFERENCES review_schema.journal_configs(id),
      ADD COLUMN IF NOT EXISTS author_name VARCHAR(255),
      ADD COLUMN IF NOT EXISTS selected_agents TEXT[] DEFAULT ARRAY['editorial', 'methodology'],
      ADD COLUMN IF NOT EXISTS editorial_score FLOAT,
      ADD COLUMN IF NOT EXISTS methodology_status VARCHAR(20),
      ADD COLUMN IF NOT EXISTS pico_extract JSONB,
      ADD COLUMN IF NOT EXISTS is_archived BOOLEAN DEFAULT FALSE,
      ADD COLUMN IF NOT EXISTS archived_at TIMESTAMPTZ;
    
    -- 5. 鍒涘缓绱㈠紩
    CREATE INDEX IF NOT EXISTS idx_review_tasks_journal ON review_schema.review_tasks(journal_id);
    CREATE INDEX IF NOT EXISTS idx_review_tasks_archived ON review_schema.review_tasks(is_archived);
    
    -- 6. 鍒涘缓榛樿<E6A69B>鏈熷垔閰嶇疆
    INSERT INTO review_schema.journal_configs (name, default_model)
    VALUES ('榛樿<E6A69B>鏈熷垔', 'deepseek-v3');
    
  • 2.4 鏇存柊Prisma Schema

    • <EFBFBD>@@schema("review_schema")
    • 娣诲姞鏂板瓧娈?
  • 2.5 鎵ц<E98EB5>杩佺Щ

    npx prisma migrate dev --name rvw_schema_migration
    

Phase 2 楠岃瘉

  • 2.6 楠岃瘉鏁版嵁瀹屾暣鎬? ```sql -- 纭<><E7BAAD>鏁版嵁閲忎竴鑷? SELECT COUNT(*) FROM review_schema.review_tasks;

    -- 纭<><E7BAAD>瀛楁<E7809B><EFBFBD>敤 SELECT id, selected_agents, editorial_score FROM review_schema.review_tasks LIMIT 5;

    -- 纭<><E7BAAD>澶栭敭鍏崇郴 SELECT rt.id, rt.user_id, u.email FROM review_schema.review_tasks rt JOIN public.users u ON rt.user_id = u.id LIMIT 5;

    
    

*Phase 2 楠屾敹鏍囧噯锛?

娴嬭瘯椤? 棰勬湡缁撴灉 閫氳繃
鏁版嵁杩佺Щ 鏁版嵁閲忎竴鑷? 猬?
鏂板瓧娈? 瀛楁<EFBFBD>瀛樺湪涓斿彲鐢? 猬?
澶栭敭鍏崇郴 鍏宠仈姝e父 猬?
绱㈠紩鏈夋晥 鏌ヨ<EFBFBD>鎬ц兘姝 猬?
API姝 鍚庣<EFBFBD>API浠嶅彲鐢? 猬?
  • 2.7<><E7BAAD>Phase 2閫氳繃

Phase 3锛氬墠绔<E5A2A0>噸鏋勶紙3澶╋級

Day 3锛氭ā鍧楃粨鏋?+ API灞?

3.1 鍒涘缓妯″潡缁撴瀯

frontend-v2/src/modules/rvw/
鈹溾攢鈹€ api/
鈹?  鈹斺攢鈹€ reviewApi.ts              # API灏佽<E7818F>
鈹溾攢鈹€ components/
鈹?  鈹溾攢鈹€ ScoreCard.tsx             # 澶嶇敤
鈹?  鈹溾攢鈹€ EditorialReview.tsx       # 澶嶇敤
鈹?  鈹溾攢鈹€ MethodologyReview.tsx     # 澶嶇敤
鈹?  鈹溾攢鈹€ AgentSelector.tsx         # 馃啎 鏅鸿兘浣撻€夋嫨寮圭獥
鈹?  鈹溾攢鈹€ BatchToolbar.tsx          # 馃啎 鎵归噺鎿嶄綔鏍?鈹?  鈹溾攢鈹€ TaskTable.tsx             # 馃啎 浠诲姟鍒楄〃琛ㄦ牸
鈹?  鈹斺攢鈹€ StatusFilter.tsx          # 馃啎 鐘舵€佺瓫閫?鈹溾攢鈹€ pages/
鈹?  鈹溾攢鈹€ ReviewDashboard.tsx       # 馃啎 瀹$ǹ宸ヤ綔鍙?鈹?  鈹斺攢鈹€ ReviewDetail.tsx          # 鎶ュ憡璇︽儏锛堜紭鍖栵級
鈹溾攢鈹€ hooks/
鈹?  鈹溾攢鈹€ useReviewTask.ts
鈹?  鈹斺攢鈹€ useBatchOperation.ts
鈹溾攢鈹€ stores/
鈹?  鈹斺攢鈹€ useReviewStore.ts
鈹溾攢鈹€ types/
鈹?  鈹斺攢鈹€ index.ts
鈹斺攢鈹€ index.tsx
  • 3.1.1 鍒涘缓鐩<E7BC93>綍缁撴瀯
  • 3.1.2 澶嶇敤鐜版湁缁勪欢锛圫coreCard銆丒ditorialReview銆丮ethodologyReview锛? 3.2 API灏佽<E7818F>
// api/reviewApi.ts
export type AgentType = 'editorial' | 'methodology';

// 杩愯<E69DA9>瀹℃煡锛堟敮鎸侀€夋嫨鏅鸿兘浣擄級
export async function runReview(taskId: string, agents: AgentType[]): Promise<void> {
  return axios.post(`/api/v1/rvw/tasks/${taskId}/run`, { agents });
}

// 鎵归噺杩愯<E69DA9>
export async function batchRunReview(taskIds: string[], agents: AgentType[]): Promise<void> {
  return axios.post('/api/v1/rvw/tasks/batch/run', { taskIds, agents });
}

// 鑾峰彇浠诲姟鍒楄〃锛堝甫绛涢€夛級
export interface TaskListParams {
  status?: 'all' | 'pending' | 'completed';
  limit?: number;
  offset?: number;
}

export async function getTaskList(params: TaskListParams): Promise<TaskListResponse> {
  return axios.get('/api/v1/rvw/tasks', { params });
}
  • 3.2.1 瀹炵幇API灏佽<E7818F>
  • 3.2.2 瀹炵幇绫诲瀷瀹氫箟

Day 4锛氭牳蹇冮〉闈㈠紑鍙?

3.3 鏅鸿兘浣撻€夋嫨寮圭獥

// components/AgentSelector.tsx
interface AgentSelectorProps {
  visible: boolean;
  taskIds: string[];           // 鏀<>寔鍗曚釜鎴栧<E98EB4>涓?  onConfirm: (agents: AgentType[]) => void;
  onCancel: () => void;
}

// 寮圭獥鍐呭<E98D90>锛?// 鉁?绋跨害瑙勮寖鎬ф櫤鑳戒綋锛堥粯璁ら€変腑锛?//    鏍煎紡銆佸弬鑰冩枃鐚<E69E83>€佸浘鐗囨<E99097>鏌?// 鈽?鏂规硶瀛︾粺璁℃櫤鑳戒綋
//    DeepSeek 娣卞害閫昏緫鎺ㄧ悊
//
// 鎻愮ず锛氬彲閫夋嫨1涓<31>垨鍚屾椂閫夋嫨2涓<32>櫤鑳戒綋
//
// [鍙栨秷] [绔嬪嵆杩愯<E69DA9>]
  • 3.3.1 瀹炵幇鏅鸿兘浣撻€夋嫨寮圭獥
  • 3.3.2<>寔鍗曢€夊拰澶氶€?- [ ] 3.3.3 榛樿<E6A69B>閫変腑瑙勮寖鎬ф櫤鑳戒綋

*3.4 瀹$ǹ宸ヤ綔鍙?

鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?鈹? Header: [Logo] 鏅鸿兘瀹$ǹ绯荤粺                      [涓婁紶鏂扮ǹ浠禲  鈹?鈹溾攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?鈹? Filter: [鍏ㄩ儴|寰呭<E5AFB0>鐞唡宸插畬鎴怾                                   鈹?鈹溾攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?鈹? 鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹?鈹? 鈹? 鈽? 鏂囦欢鍚嶇О/淇℃伅        涓婁紶鏃堕棿  瀹$ǹ缁村害  缁撴灉鎽樿<E98EBD>  鎿嶄綔  鈹? 鈹?鈹? 鈹? 鈽? 鏇块浄鍒╃彔鍗曟姉...pdf   10:30    [瑙勮寖][鏂规硶]  92鍒?   [鏌ョ湅] 鈹?鈹? 鈹? 鈽? 楂樿<E6A582>鍘嬭嵂鐗?..docx    鍒氬垰     [鏈<>繍琛宂     绛夊緟...  [寮€濮媇 鈹?鈹? 鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹?鈹溾攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?鈹? [Batch Toolbar: 3涓<33>枃浠跺凡閫変腑 | 杩愯<E69DA9>鏅鸿兘瀹ǹ | 鉁昡              鈹?鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?```

- [ ] **3.4.1** 瀹炵幇椤甸潰甯冨眬
- [ ] **3.4.2** 瀹炵幇浠诲姟鍒楄〃琛ㄦ牸
- [ ] **3.4.3** 瀹炵幇鐘舵€佺瓫閫?- [ ] **3.4.4** 瀹炵幇鎵归噺鎿嶄綔鏍?
#### Day 5锛氭姤鍛婅<E98D9B>鎯?+ Phase 3 楠岃瘉

**3.5 鎶ュ憡璇︽儏椤?*

- [ ] **3.5.1** 瀹炵幇Tab鍒囨崲锛堣<E9949B>鑼冩€?鏂规硶瀛︼級
- [ ] **3.5.2** 澶嶇敤璇勪及璇︽儏缁勪欢
- [ ] **3.5.3** 鏍规嵁閫夋嫨鐨勬櫤鑳戒綋鏄剧ず瀵瑰簲Tab
- [ ] **3.5.4** 瀹炵幇瀵煎嚭鎶ュ憡鎸夐挳

**3.6 璺<>敱閰嶇疆**

```typescript
// router/index.tsx
{
  path: '/rvw',
  children: [
    { path: '', element: <ReviewDashboard /> },
    { path: ':taskId', element: <ReviewDetail /> }
  ]
}
  • 3.6.1 閰嶇疆璺<E79686>
  • 3.6.2 娣诲姞瀵艰埅鑿滃崟

Phase 3 楠岃瘉娴嬭瘯

娴嬭瘯椤? 棰勬湡缁撴灉 閫氳繃
椤甸潰鍔犺浇 宸ヤ綔鍙版<EFBFBD>甯告樉绀? 猬?
鏂囦欢涓婁紶 <EFBFBD>寔澶氭枃浠? 猬?
鏅鸿兘浣撻€夋嫨 <EFBFBD>€?涓<>垨2涓? 猬?
鎵归噺鎿嶄綔 鎵归噺杩愯<EFBFBD>鎴愬姛 猬?
鐘舵€佺瓫閫? 绛涢€夌粨鏋滄<EFBFBD>纭? 猬?
鎶ュ憡鏌ョ湅 鏄剧ず瀵瑰簲璇勪及缁撴灉 猬?
  • 3.7<><E7BAAD>Phase 3閫氳繃

Phase 4锛氶泦鎴愭祴璇曪紙1澶╋級

*4.1 绔<>埌绔<E59F8C>祴璇?

娴嬭瘯鍦烘櫙 姝ラ<EFBFBD> 棰勬湡缁撴灉
鍗曟枃浠?鍗曟櫤鑳戒綋 涓婁紶鈫掗€夎<EFBFBD>鑼冩€р啋鏌ョ湅 <EFBFBD>樉绀鸿<EFBFBD>鑼冩€ф姤鍛?
鍗曟枃浠?鍙屾櫤鑳戒綋 涓婁紶鈫掗€変袱涓<EFBFBD>啋鏌ョ湅 鏄剧ず涓や釜鎶ュ憡Tab
鎵归噺+鍙屾櫤鑳戒綋 涓婁紶3涓<EFBFBD>啋鎵归噺杩愯<EFBFBD> 3涓<EFBFBD>兘瀹屾垚
鐘舵€佺瓫閫? 涓婁紶鈫掔瓫閫夊緟澶勭悊 姝g‘杩囨护
  • 4.1.1 鎵ц<E98EB5><EFBFBD>埌绔<E59F8C>祴璇?- [ ] 4.1.2<><E6B787>鍙戠幇鐨勯棶棰? 4.2 鎬ц兘娴嬭瘯
鎸囨爣 <EFBFBD> 瀹為檯
鍒楄〃鍔犺浇 < 1绉? 猬?
鍗曟枃浠跺<EFBFBD>鏌? < 2鍒嗛挓 猬?
5鏂囦欢骞跺彂 < 5鍒嗛挓 猬?
  • 4.2.1 鎵ц<E98EB5>鎬ц兘娴嬭瘯

*4.3 鍏煎<E98D8F>鎬ф祴璇?

  • 4.3.1 Chrome娴忚<E5A8B4>鍣ㄦ祴璇?- [ ] 4.3.2 Edge娴忚<E5A8B4>鍣ㄦ祴璇?- [ ] 4.3.3<>PI鍏煎<E98D8F>х璁?

Phase 5锛氶獙鏀朵笌涓婄嚎锛?.5澶╋級

5.1 MVP楠屾敹鏍囧噯

楠屾敹椤? 棰勬湡缁撴灉 閫氳繃
娴佺▼閫? 5涓狿DF锛?鍒嗛挓鍐呭叏閮ㄥ畬鎴? 猬?
瑙勮寖鎬у噯纭? 鍒犳帀鎽樿<EFBFBD>缁撹<EFBFBD>蹇呴』鎶ラ敊 猬?
鏂规硶瀛﹀噯纭? 娣锋穯缁熻<EFBFBD>鏂规硶蹇呴』鎶ュ瓨鐤? 猬?
鏃犲穿婧? 杩炵画涓婁紶20涓<EFBFBD>笉鍗℃<EFBFBD> 猬?
  • 5.1.1 鎵ц<E98EB5>楠屾敹娴嬭瘯
  • 5.1.2 缂栧啓楠屾敹鎶ュ憡

5.2 涓婄嚎鍑嗗<E98D91>

  • 5.2.1 鏇存柊鏂囨。
  • 5.2.2 閫氱煡鐩稿叧浜哄憳
  • 5.2.3 鐩戞帶涓婄嚎鍚庣姸鎬?

馃搮 鏃堕棿浼扮畻

Phase 浠诲姟 棰勪及宸ユ椂 楠岃瘉鐐?
Phase 1 鍚庣<EFBFBD>妯″潡杩佺Щ 2澶? 鉁?API娴嬭瘯閫氳繃
Phase 2 鏁版嵁搴撹縼绉? 0.5澶? 鉁?鏁版嵁瀹屾暣鎬ч獙璇?
Phase 3 鍓嶇<EFBFBD>閲嶆瀯 3澶? 鉁?鍔熻兘娴嬭瘯閫氳繃
Phase 4 闆嗘垚娴嬭瘯 1澶? 鉁?绔<>埌绔<E59F8C>祴璇曢€氳繃
Phase 5 楠屾敹涓婄嚎 0.5澶? 鉁?MVP楠屾敹閫氳繃
鎬昏<EFBFBD> - *7澶? -

鈴革笍 鏆備笉寮€鍙戠殑鍔熻兘锛堟暟鎹<E69A9F>簱宸查<E5AEB8>鐣欙級

鍔熻兘 棰勭暀瀛楁<EFBFBD> 鍚庣画璁″垝
PICO鍗 pico_extract 鏂规硶瀛﹁瘎浼版墿灞?
绯荤粺璁剧疆 JournalConfig琛? 鏈熷垔Logo/妯″瀷閰嶇疆
鍘嗗彶褰掓。 is_archived, archived_at <EFBFBD>姩褰掓。7澶╁墠鏁版嵁
鐧诲綍椤甸潰 - <EFBFBD>珛浜у搧鏃跺紑鍙?

鈿狅笍 椋庨櫓鎺у埗

1. 鏁版嵁搴撹縼绉婚<E7BB89>闄?

椋庨櫓 姒傜巼 褰卞搷 у埗鎺<EFBFBD>
鏁版嵁涓㈠け 浣? 楂? 杩佺Щ鍓嶅<EFBFBD>浠?
杩佺Щ澶辫触 涓? 涓? 鍑嗗<EFBFBD>鍥炴粴SQL
鎬ц兘涓嬮檷 浣? 涓? 楠岃瘉绱㈠紩鏈夋晥鎬?

2. 鍔熻兘鍥炲綊椋庨櫓

椋庨櫓 姒傜巼 褰卞搷 у埗鎺<EFBFBD>
<EFBFBD>PI涓<EFBFBD> 浣? 楂? 淇濈暀v1璺<EFBFBD>
璇勪及缁撴灉寮傚父 浣? 楂? 瀵规瘮娴嬭瘯缁撴灉
鍓嶇<EFBFBD>鐧藉睆 涓? 涓? 闃舵<EFBFBD>鎬ф祴璇?

3. 鍥炴粴璁″垝

# 濡傛灉闇€瑕佸洖婊氬埌杩佺Щ鍓嶇姸鎬?
# 1. 鍋滄<E98D8B>鏈嶅姟
pm2 stop all

# 2. 鍥炴粴鏁版嵁搴?pg_restore -h localhost -U postgres -d airesearch -c backup_phase2.dump

# 3. 鍒囨崲鍒版棫浠g爜鍒嗘敮
git checkout main

# 4. 閲嶅惎鏈嶅姟
pm2 start all

馃摎 鍙傝€冩枃妗?


*鏂囨。鐗堟湰锛? v2.1
鏈€鍚庢洿鏂帮細 2026-01-07
涓嬩竴姝ワ細<><E7BAAD>鍚庡紑濮婸hase 1