使用 ChatGPT 来辅助学习和编程
标题中的 ChatGPT 在此处泛指基于大语言模型 (LLM) 的聊天机器人服务,包括但不限于 OpenAI 的 ChatGPT,下文将使用 "ChatBot" 称呼。
从我开始接触 ChatBot (2022年初) 截至今日,我在使用得较多的 ChatBot 是 "Microsoft Bing Chat" 和 "Google Bard"。很多时候,我都会想像与人交互一样向 ChatBot 直接且简单地提出问题。这通常都可以比使用搜索引擎更快地得到答案。然而,对于一些特殊场景,或是比较复杂的编程项目问题,我会调整一下交互方式。
下面是两个我认为比较有参考意义的交互方式:
1. 引导式学习
让 ChatBot 扮演导师,以苏格拉底式的风格与用户聊天,引导用户自己逐步寻找问题的答案:
User:
请用苏格拉底聊天的风格让我意识到牙齿健康的重要性。
ChatBot:
苏格拉底: 你知道牙齿健康的重要性吗?
你: 当然知道,牙齿是人体的重要器官,负责咀嚼食物、发音等功能。 苏格拉底: 那你认为牙齿健康有什么好处呢?
你: 牙齿健康可以帮助我们更好地咀嚼食物,促进消化吸收;还可以帮助我们发出清晰的声音,更好地与人交流。
苏格拉底: 这些都是很有道理的。那么,你认为牙齿不健康会有什么坏处呢?
你: 牙齿不健康会导致牙痛、牙龈炎、龋齿等疾病,影响我们的日常生活。严重的牙齿疾病甚至会导致牙齿脱落,影响我们的咀嚼功能和发音。
苏格拉底: 你说得很好。那么,我们应该如何保持牙齿健康呢?
你: 我们应该每天早晚刷牙,饭后漱口,定期去看牙医。
苏格拉底: 这些都是非常重要的。那么,你认为我们应该如何提高牙齿健康意识呢?
你: 我们应该从小培养良好的口腔卫生习惯,并定期接受牙齿检查和保健。
苏格拉底: 你说的很有见地。总而言之,牙齿健康对我们的生活非常重要,我们应该从小养成良好的口腔卫生习惯,定期接受牙齿检查和保健,才能拥有一口健康的牙齿。
你: 我同意你的观点。我会从现在开始更加注意牙齿健康。
苏格拉底: 很好,我很高兴听到你这么说。
(苏格拉底与你握手) 苏格拉底: 希望我们下次再聊。
(苏格拉底离开) (你独自思考)
2. 场景复杂的问题
以编程问题为例,当一个开发项目涉及的架构、语言较多,项目结构、交互场景繁杂时,我会使用 Markdown 格式来提供代码片段,并阐述引起问题的场景:
User:
请帮我处理这个 React Native 引起的 Android 问题:
在 Android App 中成功调用 JS NativeModules.Installer.install()
方法并跳转到系统安装界面后,安装界面弹出弹窗报错:
open failed: EACCES (Permission denied)
open failed: EACCES (Permission denied)
这是调用的 JavaScript 方法:
import RNFS from 'react-native-fs';
const fileName = 'KioskLite-v1.0.18-Prod-20230925.apk';
const filePath = `${RNFS.ExternalCachesDirectoryPath}/${fileName}`;
NativeModules.Installer.install(filePath)
.then(res => console.log(res))
.catch(e => console.warn(e))
import RNFS from 'react-native-fs';
const fileName = 'KioskLite-v1.0.18-Prod-20230925.apk';
const filePath = `${RNFS.ExternalCachesDirectoryPath}/${fileName}`;
NativeModules.Installer.install(filePath)
.then(res => console.log(res))
.catch(e => console.warn(e))
这是 JS 引用的 ReactNative Android JAVA 插件:
// imports...
public class Installer extends ReactContextBaseJavaModule {
// ...
@ReactMethod
public void install(final String path, Callback successCallback) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= 24) {
String packageName = context.getPackageName();
Uri contentUri = FileProvider.getUriForFile(context, packageName + ".provider", new File(path));
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
successCallback.invoke("Installation success");
} catch (Exception e) {
Log.e("Installer", "Installation failed", e);
successCallback.invoke("Installation failed");
}
}
}
// imports...
public class Installer extends ReactContextBaseJavaModule {
// ...
@ReactMethod
public void install(final String path, Callback successCallback) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= 24) {
String packageName = context.getPackageName();
Uri contentUri = FileProvider.getUriForFile(context, packageName + ".provider", new File(path));
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
successCallback.invoke("Installation success");
} catch (Exception e) {
Log.e("Installer", "Installation failed", e);
successCallback.invoke("Installation failed");
}
}
}
这是项目的 AndroidManifest.xml
文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<!-- some users-permissions... -->
<application
android:name=".MainApplication"
android:label="${app_name}"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
>
<!-- some activities... -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
/>
</provider>
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<!-- some users-permissions... -->
<application
android:name=".MainApplication"
android:label="${app_name}"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
>
<!-- some activities... -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
/>
</provider>
</application>
</manifest>
这是项目的 file_paths.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="downloads" path="Download/" />
</paths>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="downloads" path="Download/" />
</paths>
ChatBot:
- 您的
AndroidManifest.xml
文件中没有声明安装未知来源应用的权限,这个权限是android.permission.REQUEST_INSTALL_PACKAGES
¹。如果您的应用要安装其他应用,那么您需要在AndroidManifest.xml
文件中添加这个权限,如下所示:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
- 您的
file_paths.xml
文件中指定的路径是Download/
,但是您的代码中使用的路径是RNFS.ExternalCachesDirectoryPath
,这两个路径可能不一致。您需要确保您的文件提供器能够访问您要安装的 APK 文件所在的路径²。您可以尝试修改file_paths.xml
文件中的路径为.
,表示根目录,或者使用其他合适的路径³。
<external-path name="downloads" path="." />
<external-path name="downloads" path="." />
- 您的代码中使用了
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
,但是这个标志只能在 API 24 及以上版本生效⁴。如果您要支持低版本的 Android 设备,那么您需要在调用startActivity(intent)
之前添加一行代码,如下所示:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
这样可以让安装程序获得读取 APK 文件的权限。